From dd0c39e0414e30e98271836b99ef289d04b7d569 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Wed, 1 Apr 2020 13:55:38 -0400 Subject: [PATCH 001/420] Don't accidentally return early from CopyOutReader The COPY OUT protocol allows sending CopyData packets that have no data. The (synchronous) CopyOutReader needs to be careful not to return an empty slice in this case, but instead request more data, since an empty slice is taken to mean EOF. --- postgres/src/copy_out_reader.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres/src/copy_out_reader.rs b/postgres/src/copy_out_reader.rs index a205d1a1a..92abebced 100644 --- a/postgres/src/copy_out_reader.rs +++ b/postgres/src/copy_out_reader.rs @@ -34,7 +34,7 @@ impl Read for CopyOutReader<'_> { impl BufRead for CopyOutReader<'_> { fn fill_buf(&mut self) -> io::Result<&[u8]> { - if !self.cur.has_remaining() { + while !self.cur.has_remaining() { let mut stream = self.stream.pinned(); match self .connection @@ -42,7 +42,7 @@ impl BufRead for CopyOutReader<'_> { { Ok(Some(cur)) => self.cur = cur, Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), - Ok(None) => {} + Ok(None) => break, }; } From 64d6e97effbea03d3c7baf9eded405ef1ffbde43 Mon Sep 17 00:00:00 2001 From: Nathan VanBenschoten Date: Fri, 1 May 2020 12:55:48 -0400 Subject: [PATCH 002/420] Re-add savepoint method to Transaction Revives #184. The rewrite for async/await and Tokio accidentally lost functionality that allowed users to assign specific names to savepoints when using nested transactions. This functionality had originally been added in #184 and had been updated in #374. This commit revives this functionality using a similar scheme to the one that existed before. This should allow CockroachDB users to update to the next patch release of version `0.17`. --- postgres/src/test.rs | 51 +++++++++++++++++++++++++++++++ postgres/src/transaction.rs | 13 +++++++- tokio-postgres/src/transaction.rs | 49 ++++++++++++++++++++--------- 3 files changed, 97 insertions(+), 16 deletions(-) diff --git a/postgres/src/test.rs b/postgres/src/test.rs index 9edde8e32..6750118ba 100644 --- a/postgres/src/test.rs +++ b/postgres/src/test.rs @@ -151,6 +151,57 @@ fn nested_transactions() { assert_eq!(rows[2].get::<_, i32>(0), 4); } +#[test] +fn savepoints() { + let mut client = Client::connect("host=localhost port=5433 user=postgres", NoTls).unwrap(); + + client + .batch_execute("CREATE TEMPORARY TABLE foo (id INT PRIMARY KEY)") + .unwrap(); + + let mut transaction = client.transaction().unwrap(); + + transaction + .execute("INSERT INTO foo (id) VALUES (1)", &[]) + .unwrap(); + + let mut savepoint1 = transaction.savepoint("savepoint1").unwrap(); + + savepoint1 + .execute("INSERT INTO foo (id) VALUES (2)", &[]) + .unwrap(); + + savepoint1.rollback().unwrap(); + + let rows = transaction + .query("SELECT id FROM foo ORDER BY id", &[]) + .unwrap(); + assert_eq!(rows.len(), 1); + assert_eq!(rows[0].get::<_, i32>(0), 1); + + let mut savepoint2 = transaction.savepoint("savepoint2").unwrap(); + + savepoint2 + .execute("INSERT INTO foo (id) VALUES(3)", &[]) + .unwrap(); + + let mut savepoint3 = savepoint2.savepoint("savepoint3").unwrap(); + + savepoint3 + .execute("INSERT INTO foo (id) VALUES(4)", &[]) + .unwrap(); + + savepoint3.commit().unwrap(); + savepoint2.commit().unwrap(); + transaction.commit().unwrap(); + + let rows = client.query("SELECT id FROM foo ORDER BY id", &[]).unwrap(); + assert_eq!(rows.len(), 3); + assert_eq!(rows[0].get::<_, i32>(0), 1); + assert_eq!(rows[1].get::<_, i32>(0), 3); + assert_eq!(rows[2].get::<_, i32>(0), 4); +} + #[test] fn copy_in() { let mut client = Client::connect("host=localhost port=5433 user=postgres", NoTls).unwrap(); diff --git a/postgres/src/transaction.rs b/postgres/src/transaction.rs index 25bfff578..1a021cd0a 100644 --- a/postgres/src/transaction.rs +++ b/postgres/src/transaction.rs @@ -173,7 +173,7 @@ impl<'a> Transaction<'a> { CancelToken::new(self.transaction.cancel_token()) } - /// Like `Client::transaction`. + /// Like `Client::transaction`, but creates a nested transaction via a savepoint. pub fn transaction(&mut self) -> Result, Error> { let transaction = self.connection.block_on(self.transaction.transaction())?; Ok(Transaction { @@ -181,4 +181,15 @@ impl<'a> Transaction<'a> { transaction, }) } + /// Like `Client::transaction`, but creates a nested transaction via a savepoint with the specified name. + pub fn savepoint(&mut self, name: I) -> Result, Error> + where + I: Into, + { + let transaction = self.connection.block_on(self.transaction.savepoint(name))?; + Ok(Transaction { + connection: self.connection.as_ref(), + transaction, + }) + } } diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index a1ee4f6cb..38fdf7cea 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -23,20 +23,26 @@ use tokio::io::{AsyncRead, AsyncWrite}; /// transaction. Transactions can be nested, with inner transactions implemented via safepoints. pub struct Transaction<'a> { client: &'a mut Client, - depth: u32, + savepoint: Option, done: bool, } +/// A representation of a PostgreSQL database savepoint. +struct Savepoint { + name: String, + depth: u32, +} + impl<'a> Drop for Transaction<'a> { fn drop(&mut self) { if self.done { return; } - let query = if self.depth == 0 { - "ROLLBACK".to_string() + let query = if let Some(sp) = self.savepoint.as_ref() { + format!("ROLLBACK TO {}", sp.name) } else { - format!("ROLLBACK TO sp{}", self.depth) + "ROLLBACK".to_string() }; let buf = self.client.inner().with_buf(|buf| { frontend::query(&query, buf).unwrap(); @@ -53,7 +59,7 @@ impl<'a> Transaction<'a> { pub(crate) fn new(client: &'a mut Client) -> Transaction<'a> { Transaction { client, - depth: 0, + savepoint: None, done: false, } } @@ -61,10 +67,10 @@ impl<'a> Transaction<'a> { /// Consumes the transaction, committing all changes made within it. pub async fn commit(mut self) -> Result<(), Error> { self.done = true; - let query = if self.depth == 0 { - "COMMIT".to_string() + let query = if let Some(sp) = self.savepoint.as_ref() { + format!("RELEASE {}", sp.name) } else { - format!("RELEASE sp{}", self.depth) + "COMMIT".to_string() }; self.client.batch_execute(&query).await } @@ -74,10 +80,10 @@ impl<'a> Transaction<'a> { /// This is equivalent to `Transaction`'s `Drop` implementation, but provides any error encountered to the caller. pub async fn rollback(mut self) -> Result<(), Error> { self.done = true; - let query = if self.depth == 0 { - "ROLLBACK".to_string() + let query = if let Some(sp) = self.savepoint.as_ref() { + format!("ROLLBACK TO {}", sp.name) } else { - format!("ROLLBACK TO sp{}", self.depth) + "ROLLBACK".to_string() }; self.client.batch_execute(&query).await } @@ -272,15 +278,28 @@ impl<'a> Transaction<'a> { self.client.cancel_query_raw(stream, tls).await } - /// Like `Client::transaction`. + /// Like `Client::transaction`, but creates a nested transaction via a savepoint. pub async fn transaction(&mut self) -> Result, Error> { - let depth = self.depth + 1; - let query = format!("SAVEPOINT sp{}", depth); + self._savepoint(None).await + } + + /// Like `Client::transaction`, but creates a nested transaction via a savepoint with the specified name. + pub async fn savepoint(&mut self, name: I) -> Result, Error> + where + I: Into, + { + self._savepoint(Some(name.into())).await + } + + async fn _savepoint(&mut self, name: Option) -> Result, Error> { + let depth = self.savepoint.as_ref().map_or(0, |sp| sp.depth) + 1; + let name = name.unwrap_or_else(|| format!("sp_{}", depth)); + let query = format!("SAVEPOINT {}", name); self.batch_execute(&query).await?; Ok(Transaction { client: self.client, - depth, + savepoint: Some(Savepoint { name, depth }), done: false, }) } From 66f5a8bbc58f92b5b048f75db7e036eec646f503 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 May 2020 16:10:41 -0700 Subject: [PATCH 003/420] Release tokio-postgres v0.5.4 --- tokio-postgres/CHANGELOG.md | 6 ++++++ tokio-postgres/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index e65f00f14..de25e5616 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.5.4- 2020-05-01 + +### Added + +* Added `Transaction::savepoint`, which can be used to create a savepoint with a custom name. + ## v0.5.3 - 2020-03-05 ### Added diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index d1571c352..46a86d1e7 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.5.3" +version = "0.5.4" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From f9ba58967ba2bbbbb6ff9c84a07adae246a8e316 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 1 May 2020 16:15:31 -0700 Subject: [PATCH 004/420] Release postgres v0.17.3 --- postgres/CHANGELOG.md | 11 +++++++++++ postgres/Cargo.toml | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index 550f0c706..d951ed445 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,5 +1,16 @@ # Change Log +## v0.17.3 - 2020-05-01 + +### Fixed + +* Errors sent by the server will now be returned from `Client` methods rather than just being logs. + +### Added + +* Added `Transaction::savepoint`, which can be used to create a savepoint with a custom name. +* Added `Client::notifications`, which returns an interface to the notifications sent by the server. + ## v0.17.2 - 2020-03-05 ### Added diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index d0cf11004..601095da0 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.17.2" +version = "0.17.3" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -33,7 +33,7 @@ with-time-0_2 = ["tokio-postgres/with-time-0_2"] bytes = "0.5" fallible-iterator = "0.2" futures = "0.3" -tokio-postgres = { version = "0.5.3", path = "../tokio-postgres" } +tokio-postgres = { version = "0.5.4", path = "../tokio-postgres" } tokio = { version = "0.2", features = ["rt-core", "time"] } log = "0.4" From a1efddd64a47aca595d5801a6ae40c51832eb0cf Mon Sep 17 00:00:00 2001 From: Naim A <227396+naim94a@users.noreply.github.com> Date: Tue, 12 May 2020 13:35:10 +0300 Subject: [PATCH 005/420] fix typo --- postgres/src/lib.rs | 2 +- tokio-postgres/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres/src/lib.rs b/postgres/src/lib.rs index 80380a87e..92a75bd84 100644 --- a/postgres/src/lib.rs +++ b/postgres/src/lib.rs @@ -57,7 +57,7 @@ //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | //! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | //! | `with-geo-types-0_4` | Enable support for the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types) 0.4 | no | -//! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [eui48](https://crates.io/crates/serde_json) 1.0 | no | +//! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | //! | `with-time-0_2` | Enable support for the `time` crate. | [time](https://crates.io/crates/time) 0.2 | no | #![doc(html_root_url = "https://docs.rs/postgres/0.17")] diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 2845fcf61..9e7210507 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -108,7 +108,7 @@ //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | //! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | //! | `with-geo-types-0_4` | Enable support for the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types) 0.4 | no | -//! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [eui48](https://crates.io/crates/serde_json) 1.0 | no | +//! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | //! | `with-time-0_2` | Enable support for the `time` crate. | [time](https://crates.io/crates/time) 0.2 | no | #![doc(html_root_url = "https://docs.rs/tokio-postgres/0.5")] From 887be868164ae53d1938a6669b1ca30176d52678 Mon Sep 17 00:00:00 2001 From: Jakub Wieczorek Date: Mon, 25 May 2020 12:08:17 +0200 Subject: [PATCH 006/420] Add support for geo-types=0.5 Support for geo-types=0.4 (via the `with-geo-types_04` feature) has been preserved for convenience. --- postgres-types/Cargo.toml | 2 + postgres-types/src/geo_types_05.rs | 72 ++++++++++++++++++++++++++++++ postgres-types/src/lib.rs | 2 + postgres/Cargo.toml | 1 + postgres/src/lib.rs | 3 +- tokio-postgres/Cargo.toml | 2 + tokio-postgres/src/lib.rs | 3 +- 7 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 postgres-types/src/geo_types_05.rs diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index a12f1f513..57cc79c85 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -16,6 +16,7 @@ with-bit-vec-0_6 = ["bit-vec-06"] with-chrono-0_4 = ["chrono-04"] with-eui48-0_4 = ["eui48-04"] with-geo-types-0_4 = ["geo-types-04"] +with-geo-types-0_5 = ["geo-types-05"] with-serde_json-1 = ["serde-1", "serde_json-1"] with-uuid-0_8 = ["uuid-08"] with-time-0_2 = ["time-02"] @@ -30,6 +31,7 @@ bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } chrono-04 = { version = "0.4", package = "chrono", optional = true } eui48-04 = { version = "0.4", package = "eui48", optional = true } geo-types-04 = { version = "0.4", package = "geo-types", optional = true } +geo-types-05 = { version = "0.5", package = "geo-types", optional = true } serde-1 = { version = "1.0", package = "serde", optional = true } serde_json-1 = { version = "1.0", package = "serde_json", optional = true } uuid-08 = { version = "0.8", package = "uuid", optional = true } diff --git a/postgres-types/src/geo_types_05.rs b/postgres-types/src/geo_types_05.rs new file mode 100644 index 000000000..f169134e3 --- /dev/null +++ b/postgres-types/src/geo_types_05.rs @@ -0,0 +1,72 @@ +use bytes::BytesMut; +use fallible_iterator::FallibleIterator; +use geo_types_05::{Coordinate, LineString, Point, Rect}; +use postgres_protocol::types; +use std::error::Error; + +use crate::{FromSql, IsNull, ToSql, Type}; + +impl<'a> FromSql<'a> for Point { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let point = types::point_from_sql(raw)?; + Ok(Point::new(point.x(), point.y())) + } + + accepts!(POINT); +} + +impl ToSql for Point { + fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result> { + types::point_to_sql(self.x(), self.y(), out); + Ok(IsNull::No) + } + + accepts!(POINT); + to_sql_checked!(); +} + +impl<'a> FromSql<'a> for Rect { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let rect = types::box_from_sql(raw)?; + Ok(Rect::new( + (rect.lower_left().x(), rect.lower_left().y()), + (rect.upper_right().x(), rect.upper_right().y()), + )) + } + + accepts!(BOX); +} + +impl ToSql for Rect { + fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result> { + types::box_to_sql(self.min().x, self.min().y, self.max().x, self.max().y, out); + Ok(IsNull::No) + } + + accepts!(BOX); + to_sql_checked!(); +} + +impl<'a> FromSql<'a> for LineString { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let path = types::path_from_sql(raw)?; + let points = path + .points() + .map(|p| Ok(Coordinate { x: p.x(), y: p.y() })) + .collect()?; + Ok(LineString(points)) + } + + accepts!(PATH); +} + +impl ToSql for LineString { + fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result> { + let closed = false; // always encode an open path from LineString + types::path_to_sql(closed, self.0.iter().map(|p| (p.x, p.y)), out)?; + Ok(IsNull::No) + } + + accepts!(PATH); + to_sql_checked!(); +} diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 1479c1264..b1bb0300d 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -196,6 +196,8 @@ mod chrono_04; mod eui48_04; #[cfg(feature = "with-geo-types-0_4")] mod geo_types_04; +#[cfg(feature = "with-geo-types-0_5")] +mod geo_types_05; #[cfg(feature = "with-serde_json-1")] mod serde_json_1; #[cfg(feature = "with-time-0_2")] diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 601095da0..4742396e3 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -25,6 +25,7 @@ with-bit-vec-0_6 = ["tokio-postgres/with-bit-vec-0_6"] with-chrono-0_4 = ["tokio-postgres/with-chrono-0_4"] with-eui48-0_4 = ["tokio-postgres/with-eui48-0_4"] with-geo-types-0_4 = ["tokio-postgres/with-geo-types-0_4"] +with-geo-types-0_5 = ["tokio-postgres/with-geo-types-0_5"] with-serde_json-1 = ["tokio-postgres/with-serde_json-1"] with-uuid-0_8 = ["tokio-postgres/with-uuid-0_8"] with-time-0_2 = ["tokio-postgres/with-time-0_2"] diff --git a/postgres/src/lib.rs b/postgres/src/lib.rs index 92a75bd84..dc0fd4440 100644 --- a/postgres/src/lib.rs +++ b/postgres/src/lib.rs @@ -56,7 +56,8 @@ //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | //! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | -//! | `with-geo-types-0_4` | Enable support for the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types) 0.4 | no | +//! | `with-geo-types-0_4` | Enable support for the 0.4 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.4.0) 0.4 | no | +//! | `with-geo-types-0_5` | Enable support for the 0.5 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.5.0) 0.5 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | //! | `with-time-0_2` | Enable support for the `time` crate. | [time](https://crates.io/crates/time) 0.2 | no | diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 46a86d1e7..aaed29ae3 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -31,6 +31,7 @@ with-bit-vec-0_6 = ["postgres-types/with-bit-vec-0_6"] with-chrono-0_4 = ["postgres-types/with-chrono-0_4"] with-eui48-0_4 = ["postgres-types/with-eui48-0_4"] with-geo-types-0_4 = ["postgres-types/with-geo-types-0_4"] +with-geo-types-0_5 = ["postgres-types/with-geo-types-0_5"] with-serde_json-1 = ["postgres-types/with-serde_json-1"] with-uuid-0_8 = ["postgres-types/with-uuid-0_8"] with-time-0_2 = ["postgres-types/with-time-0_2"] @@ -60,6 +61,7 @@ bit-vec-06 = { version = "0.6", package = "bit-vec" } chrono-04 = { version = "0.4", package = "chrono" } eui48-04 = { version = "0.4", package = "eui48" } geo-types-04 = { version = "0.4", package = "geo-types" } +geo-types-05 = { version = "0.5", package = "geo-types" } serde-1 = { version = "1.0", package = "serde" } serde_json-1 = { version = "1.0", package = "serde_json" } uuid-08 = { version = "0.8", package = "uuid" } diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 9e7210507..3b96f4a0e 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -107,7 +107,8 @@ //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | //! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | -//! | `with-geo-types-0_4` | Enable support for the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types) 0.4 | no | +//! | `with-geo-types-0_4` | Enable support for the 0.4 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.4.0) 0.4 | no | +//! | `with-geo-types-0_5` | Enable support for the 0.5 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.5.0) 0.5 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | //! | `with-time-0_2` | Enable support for the `time` crate. | [time](https://crates.io/crates/time) 0.2 | no | From e7661fd71ff17acff3052db22bcf8223faeaae2e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 25 May 2020 05:48:40 -0700 Subject: [PATCH 007/420] Fix geo-types tests --- .../types/{geo_010.rs => geo_types_04.rs} | 2 +- .../tests/test/types/geo_types_05.rs | 60 +++++++++++++++++++ tokio-postgres/tests/test/types/mod.rs | 6 +- 3 files changed, 65 insertions(+), 3 deletions(-) rename tokio-postgres/tests/test/types/{geo_010.rs => geo_types_04.rs} (95%) create mode 100644 tokio-postgres/tests/test/types/geo_types_05.rs diff --git a/tokio-postgres/tests/test/types/geo_010.rs b/tokio-postgres/tests/test/types/geo_types_04.rs similarity index 95% rename from tokio-postgres/tests/test/types/geo_010.rs rename to tokio-postgres/tests/test/types/geo_types_04.rs index 6e3d835b9..b26fb4091 100644 --- a/tokio-postgres/tests/test/types/geo_010.rs +++ b/tokio-postgres/tests/test/types/geo_types_04.rs @@ -1,4 +1,4 @@ -use geo_010::{Coordinate, LineString, Point, Rect}; +use geo_types_04::{Coordinate, LineString, Point, Rect}; use crate::types::test_type; diff --git a/tokio-postgres/tests/test/types/geo_types_05.rs b/tokio-postgres/tests/test/types/geo_types_05.rs new file mode 100644 index 000000000..b53951c1d --- /dev/null +++ b/tokio-postgres/tests/test/types/geo_types_05.rs @@ -0,0 +1,60 @@ +use geo_types_05::{Coordinate, LineString, Point, Rect}; + +use crate::types::test_type; + +#[tokio::test] +async fn test_point_params() { + test_type( + "POINT", + &[ + (Some(Point::new(0.0, 0.0)), "POINT(0, 0)"), + (Some(Point::new(-3.14, 1.618)), "POINT(-3.14, 1.618)"), + (None, "NULL"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_box_params() { + test_type( + "BOX", + &[ + ( + Some(Rect::new( + Coordinate { x: -3.14, y: 1.618 }, + Coordinate { + x: 160.0, + y: 69701.5615, + }, + )), + "BOX(POINT(160.0, 69701.5615), POINT(-3.14, 1.618))", + ), + (None, "NULL"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_path_params() { + let points = vec![ + Coordinate { x: 0., y: 0. }, + Coordinate { x: -3.14, y: 1.618 }, + Coordinate { + x: 160.0, + y: 69701.5615, + }, + ]; + test_type( + "PATH", + &[ + ( + Some(LineString(points)), + "path '((0, 0), (-3.14, 1.618), (160.0, 69701.5615))'", + ), + (None, "NULL"), + ], + ) + .await; +} diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index 5d292db52..9f96019fe 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -18,8 +18,10 @@ mod bit_vec_06; mod chrono_04; #[cfg(feature = "with-eui48-0_4")] mod eui48_04; -#[cfg(feature = "with-geo-0_10")] -mod geo_010; +#[cfg(feature = "with-geo-types-0_4")] +mod geo_types_04; +#[cfg(feature = "with-geo-types-0_5")] +mod geo_types_05; #[cfg(feature = "with-serde_json-1")] mod serde_json_1; #[cfg(feature = "with-time-0_2")] From 2b59b7e63c2013116dc0335a7e7f891cde6a235a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 25 May 2020 05:54:19 -0700 Subject: [PATCH 008/420] fix clippy --- postgres-types/src/lib.rs | 1 - tokio-postgres/tests/test/types/geo_types_04.rs | 10 +++++----- tokio-postgres/tests/test/types/geo_types_05.rs | 10 +++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index b1bb0300d..dbde5eb04 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -109,7 +109,6 @@ #![warn(clippy::all, rust_2018_idioms, missing_docs)] use fallible_iterator::FallibleIterator; -use postgres_protocol; use postgres_protocol::types::{self, ArrayDimension}; use std::any::type_name; use std::borrow::Cow; diff --git a/tokio-postgres/tests/test/types/geo_types_04.rs b/tokio-postgres/tests/test/types/geo_types_04.rs index b26fb4091..a4f0ac6f6 100644 --- a/tokio-postgres/tests/test/types/geo_types_04.rs +++ b/tokio-postgres/tests/test/types/geo_types_04.rs @@ -8,7 +8,7 @@ async fn test_point_params() { "POINT", &[ (Some(Point::new(0.0, 0.0)), "POINT(0, 0)"), - (Some(Point::new(-3.14, 1.618)), "POINT(-3.14, 1.618)"), + (Some(Point::new(-3.2, 1.618)), "POINT(-3.2, 1.618)"), (None, "NULL"), ], ) @@ -22,13 +22,13 @@ async fn test_box_params() { &[ ( Some(Rect { - min: Coordinate { x: -3.14, y: 1.618 }, + min: Coordinate { x: -3.2, y: 1.618 }, max: Coordinate { x: 160.0, y: 69701.5615, }, }), - "BOX(POINT(160.0, 69701.5615), POINT(-3.14, 1.618))", + "BOX(POINT(160.0, 69701.5615), POINT(-3.2, 1.618))", ), (None, "NULL"), ], @@ -40,7 +40,7 @@ async fn test_box_params() { async fn test_path_params() { let points = vec![ Coordinate { x: 0., y: 0. }, - Coordinate { x: -3.14, y: 1.618 }, + Coordinate { x: -3.2, y: 1.618 }, Coordinate { x: 160.0, y: 69701.5615, @@ -51,7 +51,7 @@ async fn test_path_params() { &[ ( Some(LineString(points)), - "path '((0, 0), (-3.14, 1.618), (160.0, 69701.5615))'", + "path '((0, 0), (-3.2, 1.618), (160.0, 69701.5615))'", ), (None, "NULL"), ], diff --git a/tokio-postgres/tests/test/types/geo_types_05.rs b/tokio-postgres/tests/test/types/geo_types_05.rs index b53951c1d..334dc0b13 100644 --- a/tokio-postgres/tests/test/types/geo_types_05.rs +++ b/tokio-postgres/tests/test/types/geo_types_05.rs @@ -8,7 +8,7 @@ async fn test_point_params() { "POINT", &[ (Some(Point::new(0.0, 0.0)), "POINT(0, 0)"), - (Some(Point::new(-3.14, 1.618)), "POINT(-3.14, 1.618)"), + (Some(Point::new(-3.2, 1.618)), "POINT(-3.2, 1.618)"), (None, "NULL"), ], ) @@ -22,13 +22,13 @@ async fn test_box_params() { &[ ( Some(Rect::new( - Coordinate { x: -3.14, y: 1.618 }, + Coordinate { x: -3.2, y: 1.618 }, Coordinate { x: 160.0, y: 69701.5615, }, )), - "BOX(POINT(160.0, 69701.5615), POINT(-3.14, 1.618))", + "BOX(POINT(160.0, 69701.5615), POINT(-3.2, 1.618))", ), (None, "NULL"), ], @@ -40,7 +40,7 @@ async fn test_box_params() { async fn test_path_params() { let points = vec![ Coordinate { x: 0., y: 0. }, - Coordinate { x: -3.14, y: 1.618 }, + Coordinate { x: -3.2, y: 1.618 }, Coordinate { x: 160.0, y: 69701.5615, @@ -51,7 +51,7 @@ async fn test_path_params() { &[ ( Some(LineString(points)), - "path '((0, 0), (-3.14, 1.618), (160.0, 69701.5615))'", + "path '((0, 0), (-3.2, 1.618), (160.0, 69701.5615))'", ), (None, "NULL"), ], From 58a7856646723e1bcfc06921d878a7fadc5c6281 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 10 Jun 2020 16:45:58 -0700 Subject: [PATCH 009/420] Update hmac and sha2 --- postgres-protocol/Cargo.toml | 4 +-- postgres-protocol/src/authentication/sasl.rs | 35 ++++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index ebad1aefc..d7be8eb80 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -13,9 +13,9 @@ base64 = "0.12" byteorder = "1.0" bytes = "0.5" fallible-iterator = "0.2" -hmac = "0.7" +hmac = "0.8" md5 = "0.7" memchr = "2.0" rand = "0.7" -sha2 = "0.8" +sha2 = "0.9" stringprep = "0.1" diff --git a/postgres-protocol/src/authentication/sasl.rs b/postgres-protocol/src/authentication/sasl.rs index af458bbaf..994f0c4b9 100644 --- a/postgres-protocol/src/authentication/sasl.rs +++ b/postgres-protocol/src/authentication/sasl.rs @@ -1,8 +1,9 @@ //! SASL-based authentication support. -use hmac::{Hmac, Mac}; +use hmac::{Hmac, Mac, NewMac}; use rand::{self, Rng}; use sha2::{Digest, Sha256}; +use sha2::digest::FixedOutput; use std::fmt::Write; use std::io; use std::iter; @@ -33,16 +34,16 @@ fn normalize(pass: &[u8]) -> Vec { fn hi(str: &[u8], salt: &[u8], i: u32) -> [u8; 32] { let mut hmac = Hmac::::new_varkey(str).expect("HMAC is able to accept all key sizes"); - hmac.input(salt); - hmac.input(&[0, 0, 0, 1]); - let mut prev = hmac.result().code(); + hmac.update(salt); + hmac.update(&[0, 0, 0, 1]); + let mut prev = hmac.finalize().into_bytes(); let mut hi = prev; for _ in 1..i { let mut hmac = Hmac::::new_varkey(str).expect("already checked above"); - hmac.input(prev.as_slice()); - prev = hmac.result().code(); + hmac.update(&prev); + prev = hmac.finalize().into_bytes(); for (hi, prev) in hi.iter_mut().zip(prev) { *hi ^= prev; @@ -196,12 +197,12 @@ impl ScramSha256 { let mut hmac = Hmac::::new_varkey(&salted_password) .expect("HMAC is able to accept all key sizes"); - hmac.input(b"Client Key"); - let client_key = hmac.result().code(); + hmac.update(b"Client Key"); + let client_key = hmac.finalize().into_bytes(); let mut hash = Sha256::default(); - hash.input(client_key.as_slice()); - let stored_key = hash.result(); + hash.update(client_key.as_slice()); + let stored_key = hash.finalize_fixed(); let mut cbind_input = vec![]; cbind_input.extend(channel_binding.gs2_header().as_bytes()); @@ -215,11 +216,11 @@ impl ScramSha256 { let mut hmac = Hmac::::new_varkey(&stored_key).expect("HMAC is able to accept all key sizes"); - hmac.input(auth_message.as_bytes()); - let client_signature = hmac.result(); + hmac.update(auth_message.as_bytes()); + let client_signature = hmac.finalize().into_bytes(); let mut client_proof = client_key; - for (proof, signature) in client_proof.iter_mut().zip(client_signature.code()) { + for (proof, signature) in client_proof.iter_mut().zip(client_signature) { *proof ^= signature; } @@ -267,12 +268,12 @@ impl ScramSha256 { let mut hmac = Hmac::::new_varkey(&salted_password) .expect("HMAC is able to accept all key sizes"); - hmac.input(b"Server Key"); - let server_key = hmac.result(); + hmac.update(b"Server Key"); + let server_key = hmac.finalize().into_bytes(); - let mut hmac = Hmac::::new_varkey(&server_key.code()) + let mut hmac = Hmac::::new_varkey(&server_key) .expect("HMAC is able to accept all key sizes"); - hmac.input(auth_message.as_bytes()); + hmac.update(auth_message.as_bytes()); hmac.verify(&verifier) .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "SCRAM verification error")) } From a12efc41d7656f39ad23732f735264abd654bbe1 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 10 Jun 2020 16:46:55 -0700 Subject: [PATCH 010/420] rustfmt --- postgres-protocol/src/authentication/sasl.rs | 6 +++--- postgres-types/src/lib.rs | 17 +++++++++-------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/postgres-protocol/src/authentication/sasl.rs b/postgres-protocol/src/authentication/sasl.rs index 994f0c4b9..c99a27a2e 100644 --- a/postgres-protocol/src/authentication/sasl.rs +++ b/postgres-protocol/src/authentication/sasl.rs @@ -2,8 +2,8 @@ use hmac::{Hmac, Mac, NewMac}; use rand::{self, Rng}; -use sha2::{Digest, Sha256}; use sha2::digest::FixedOutput; +use sha2::{Digest, Sha256}; use std::fmt::Write; use std::io; use std::iter; @@ -271,8 +271,8 @@ impl ScramSha256 { hmac.update(b"Server Key"); let server_key = hmac.finalize().into_bytes(); - let mut hmac = Hmac::::new_varkey(&server_key) - .expect("HMAC is able to accept all key sizes"); + let mut hmac = + Hmac::::new_varkey(&server_key).expect("HMAC is able to accept all key sizes"); hmac.update(auth_message.as_bytes()); hmac.verify(&verifier) .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "SCRAM verification error")) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index dbde5eb04..e78cedf4a 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -158,16 +158,17 @@ macro_rules! accepts { #[macro_export] macro_rules! to_sql_checked { () => { - fn to_sql_checked(&self, - ty: &$crate::Type, - out: &mut $crate::private::BytesMut) - -> ::std::result::Result<$crate::IsNull, - Box> { + fn to_sql_checked( + &self, + ty: &$crate::Type, + out: &mut $crate::private::BytesMut, + ) -> ::std::result::Result< + $crate::IsNull, + Box, + > { $crate::__to_sql_checked(self, ty, out) } - } + }; } // WARNING: this function is not considered part of this crate's public API. From 3e67dbb773d7af47e0d19d9dc3688fc5db731c0c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 10 Jun 2020 16:54:07 -0700 Subject: [PATCH 011/420] Fix clippy --- codegen/src/type_gen.rs | 45 +++++++++++----------------- postgres/src/copy_out_reader.rs | 2 +- tokio-postgres/src/error/mod.rs | 20 ++++++------- tokio-postgres/src/generic_client.rs | 1 + 4 files changed, 30 insertions(+), 38 deletions(-) diff --git a/codegen/src/type_gen.rs b/codegen/src/type_gen.rs index 99a38ce87..010b30c53 100644 --- a/codegen/src/type_gen.rs +++ b/codegen/src/type_gen.rs @@ -319,46 +319,42 @@ fn make_impl(w: &mut BufWriter, types: &BTreeMap) { .unwrap(); for (oid, type_) in types { - write!( + writeln!( w, - " {} => Some(Inner::{}), -", + " {} => Some(Inner::{}),", oid, type_.variant ) .unwrap(); } - write!( + writeln!( w, " _ => None, }} }} pub fn oid(&self) -> Oid {{ - match *self {{ -", + match *self {{", ) .unwrap(); for (oid, type_) in types { - write!( + writeln!( w, - " Inner::{} => {}, -", + " Inner::{} => {},", type_.variant, oid ) .unwrap(); } - write!( + writeln!( w, " Inner::Other(ref u) => u.oid, }} }} pub fn kind(&self) -> &Kind {{ - match *self {{ -", + match *self {{", ) .unwrap(); @@ -370,46 +366,42 @@ fn make_impl(w: &mut BufWriter, types: &BTreeMap) { _ => "Simple".to_owned(), }; - write!( + writeln!( w, " Inner::{} => {{ &Kind::{} - }} -", + }}", type_.variant, kind ) .unwrap(); } - write!( + writeln!( w, r#" Inner::Other(ref u) => &u.kind, }} }} pub fn name(&self) -> &str {{ - match *self {{ -"#, + match *self {{"#, ) .unwrap(); for type_ in types.values() { - write!( + writeln!( w, - r#" Inner::{} => "{}", -"#, + r#" Inner::{} => "{}","#, type_.variant, type_.name ) .unwrap(); } - write!( + writeln!( w, " Inner::Other(ref u) => &u.name, }} }} -}} -" +}}" ) .unwrap(); } @@ -417,12 +409,11 @@ fn make_impl(w: &mut BufWriter, types: &BTreeMap) { fn make_consts(w: &mut BufWriter, types: &BTreeMap) { write!(w, "impl Type {{").unwrap(); for type_ in types.values() { - write!( + writeln!( w, " /// {docs} - pub const {ident}: Type = Type(Inner::{variant}); -", + pub const {ident}: Type = Type(Inner::{variant});", docs = type_.doc, ident = type_.ident, variant = type_.variant diff --git a/postgres/src/copy_out_reader.rs b/postgres/src/copy_out_reader.rs index 92abebced..fd9c27fb0 100644 --- a/postgres/src/copy_out_reader.rs +++ b/postgres/src/copy_out_reader.rs @@ -38,7 +38,7 @@ impl BufRead for CopyOutReader<'_> { let mut stream = self.stream.pinned(); match self .connection - .block_on({ async { stream.next().await.transpose() } }) + .block_on(async { stream.next().await.transpose() }) { Ok(Some(cur)) => self.cur = cur, Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)), diff --git a/tokio-postgres/src/error/mod.rs b/tokio-postgres/src/error/mod.rs index 788e70cf4..0bcf0c6f9 100644 --- a/tokio-postgres/src/error/mod.rs +++ b/tokio-postgres/src/error/mod.rs @@ -224,7 +224,7 @@ impl DbError { /// /// Might run to multiple lines. pub fn detail(&self) -> Option<&str> { - self.detail.as_ref().map(|s| &**s) + self.detail.as_deref() } /// An optional suggestion what to do about the problem. @@ -233,7 +233,7 @@ impl DbError { /// (potentially inappropriate) rather than hard facts. Might run to /// multiple lines. pub fn hint(&self) -> Option<&str> { - self.hint.as_ref().map(|s| &**s) + self.hint.as_deref() } /// An optional error cursor position into either the original query string @@ -248,20 +248,20 @@ impl DbError { /// language functions and internally-generated queries. The trace is one /// entry per line, most recent first. pub fn where_(&self) -> Option<&str> { - self.where_.as_ref().map(|s| &**s) + self.where_.as_deref() } /// If the error was associated with a specific database object, the name /// of the schema containing that object, if any. (PostgreSQL 9.3+) pub fn schema(&self) -> Option<&str> { - self.schema.as_ref().map(|s| &**s) + self.schema.as_deref() } /// If the error was associated with a specific table, the name of the /// table. (Refer to the schema name field for the name of the table's /// schema.) (PostgreSQL 9.3+) pub fn table(&self) -> Option<&str> { - self.table.as_ref().map(|s| &**s) + self.table.as_deref() } /// If the error was associated with a specific table column, the name of @@ -270,14 +270,14 @@ impl DbError { /// (Refer to the schema and table name fields to identify the table.) /// (PostgreSQL 9.3+) pub fn column(&self) -> Option<&str> { - self.column.as_ref().map(|s| &**s) + self.column.as_deref() } /// If the error was associated with a specific data type, the name of the /// data type. (Refer to the schema name field for the name of the data /// type's schema.) (PostgreSQL 9.3+) pub fn datatype(&self) -> Option<&str> { - self.datatype.as_ref().map(|s| &**s) + self.datatype.as_deref() } /// If the error was associated with a specific constraint, the name of the @@ -287,12 +287,12 @@ impl DbError { /// (For this purpose, indexes are treated as constraints, even if they /// weren't created with constraint syntax.) (PostgreSQL 9.3+) pub fn constraint(&self) -> Option<&str> { - self.constraint.as_ref().map(|s| &**s) + self.constraint.as_deref() } /// The file name of the source-code location where the error was reported. pub fn file(&self) -> Option<&str> { - self.file.as_ref().map(|s| &**s) + self.file.as_deref() } /// The line number of the source-code location where the error was @@ -303,7 +303,7 @@ impl DbError { /// The name of the source-code routine reporting the error. pub fn routine(&self) -> Option<&str> { - self.routine.as_ref().map(|s| &**s) + self.routine.as_deref() } } diff --git a/tokio-postgres/src/generic_client.rs b/tokio-postgres/src/generic_client.rs index 30351bd0a..ad318e864 100644 --- a/tokio-postgres/src/generic_client.rs +++ b/tokio-postgres/src/generic_client.rs @@ -146,6 +146,7 @@ impl GenericClient for Client { impl private::Sealed for Transaction<'_> {} #[async_trait] +#[allow(clippy::needless_lifetimes)] impl GenericClient for Transaction<'_> { async fn execute(&self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where From c845a3683e9dda42c0aa9a13dd32ee1d9c74b752 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 10 Jun 2020 16:56:22 -0700 Subject: [PATCH 012/420] rustfmt --- codegen/src/type_gen.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/codegen/src/type_gen.rs b/codegen/src/type_gen.rs index 010b30c53..485442a3f 100644 --- a/codegen/src/type_gen.rs +++ b/codegen/src/type_gen.rs @@ -319,12 +319,7 @@ fn make_impl(w: &mut BufWriter, types: &BTreeMap) { .unwrap(); for (oid, type_) in types { - writeln!( - w, - " {} => Some(Inner::{}),", - oid, type_.variant - ) - .unwrap(); + writeln!(w, " {} => Some(Inner::{}),", oid, type_.variant).unwrap(); } writeln!( @@ -339,12 +334,7 @@ fn make_impl(w: &mut BufWriter, types: &BTreeMap) { .unwrap(); for (oid, type_) in types { - writeln!( - w, - " Inner::{} => {},", - type_.variant, oid - ) - .unwrap(); + writeln!(w, " Inner::{} => {},", type_.variant, oid).unwrap(); } writeln!( From 5d9acb1eb15dce2a17fc9d6f68adf6519355ebc5 Mon Sep 17 00:00:00 2001 From: Jakub Wieczorek Date: Wed, 24 Jun 2020 12:28:21 +0200 Subject: [PATCH 013/420] Add support for the 0.6 version of `geo_types`. This change drops the support for the 0.5 version by renaming the feature, as no version of `postgres` with it included has ever been released. --- postgres-types/Cargo.toml | 4 ++-- postgres-types/src/{geo_types_05.rs => geo_types_06.rs} | 2 +- postgres-types/src/lib.rs | 4 ++-- postgres/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 4 ++-- .../tests/test/types/{geo_types_05.rs => geo_types_06.rs} | 2 +- tokio-postgres/tests/test/types/mod.rs | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) rename postgres-types/src/{geo_types_05.rs => geo_types_06.rs} (97%) rename tokio-postgres/tests/test/types/{geo_types_05.rs => geo_types_06.rs} (95%) diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 57cc79c85..afda3093d 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -16,7 +16,7 @@ with-bit-vec-0_6 = ["bit-vec-06"] with-chrono-0_4 = ["chrono-04"] with-eui48-0_4 = ["eui48-04"] with-geo-types-0_4 = ["geo-types-04"] -with-geo-types-0_5 = ["geo-types-05"] +with-geo-types-0_6 = ["geo-types-06"] with-serde_json-1 = ["serde-1", "serde_json-1"] with-uuid-0_8 = ["uuid-08"] with-time-0_2 = ["time-02"] @@ -31,7 +31,7 @@ bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } chrono-04 = { version = "0.4", package = "chrono", optional = true } eui48-04 = { version = "0.4", package = "eui48", optional = true } geo-types-04 = { version = "0.4", package = "geo-types", optional = true } -geo-types-05 = { version = "0.5", package = "geo-types", optional = true } +geo-types-06 = { version = "0.6", package = "geo-types", optional = true } serde-1 = { version = "1.0", package = "serde", optional = true } serde_json-1 = { version = "1.0", package = "serde_json", optional = true } uuid-08 = { version = "0.8", package = "uuid", optional = true } diff --git a/postgres-types/src/geo_types_05.rs b/postgres-types/src/geo_types_06.rs similarity index 97% rename from postgres-types/src/geo_types_05.rs rename to postgres-types/src/geo_types_06.rs index f169134e3..0f0b14fd9 100644 --- a/postgres-types/src/geo_types_05.rs +++ b/postgres-types/src/geo_types_06.rs @@ -1,6 +1,6 @@ use bytes::BytesMut; use fallible_iterator::FallibleIterator; -use geo_types_05::{Coordinate, LineString, Point, Rect}; +use geo_types_06::{Coordinate, LineString, Point, Rect}; use postgres_protocol::types; use std::error::Error; diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index e78cedf4a..258b68edc 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -196,8 +196,8 @@ mod chrono_04; mod eui48_04; #[cfg(feature = "with-geo-types-0_4")] mod geo_types_04; -#[cfg(feature = "with-geo-types-0_5")] -mod geo_types_05; +#[cfg(feature = "with-geo-types-0_6")] +mod geo_types_06; #[cfg(feature = "with-serde_json-1")] mod serde_json_1; #[cfg(feature = "with-time-0_2")] diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 4742396e3..cd199e27f 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -25,7 +25,7 @@ with-bit-vec-0_6 = ["tokio-postgres/with-bit-vec-0_6"] with-chrono-0_4 = ["tokio-postgres/with-chrono-0_4"] with-eui48-0_4 = ["tokio-postgres/with-eui48-0_4"] with-geo-types-0_4 = ["tokio-postgres/with-geo-types-0_4"] -with-geo-types-0_5 = ["tokio-postgres/with-geo-types-0_5"] +with-geo-types-0_6 = ["tokio-postgres/with-geo-types-0_6"] with-serde_json-1 = ["tokio-postgres/with-serde_json-1"] with-uuid-0_8 = ["tokio-postgres/with-uuid-0_8"] with-time-0_2 = ["tokio-postgres/with-time-0_2"] diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index aaed29ae3..63c2dc6ce 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -31,7 +31,7 @@ with-bit-vec-0_6 = ["postgres-types/with-bit-vec-0_6"] with-chrono-0_4 = ["postgres-types/with-chrono-0_4"] with-eui48-0_4 = ["postgres-types/with-eui48-0_4"] with-geo-types-0_4 = ["postgres-types/with-geo-types-0_4"] -with-geo-types-0_5 = ["postgres-types/with-geo-types-0_5"] +with-geo-types-0_6 = ["postgres-types/with-geo-types-0_6"] with-serde_json-1 = ["postgres-types/with-serde_json-1"] with-uuid-0_8 = ["postgres-types/with-uuid-0_8"] with-time-0_2 = ["postgres-types/with-time-0_2"] @@ -61,7 +61,7 @@ bit-vec-06 = { version = "0.6", package = "bit-vec" } chrono-04 = { version = "0.4", package = "chrono" } eui48-04 = { version = "0.4", package = "eui48" } geo-types-04 = { version = "0.4", package = "geo-types" } -geo-types-05 = { version = "0.5", package = "geo-types" } +geo-types-06 = { version = "0.6", package = "geo-types" } serde-1 = { version = "1.0", package = "serde" } serde_json-1 = { version = "1.0", package = "serde_json" } uuid-08 = { version = "0.8", package = "uuid" } diff --git a/tokio-postgres/tests/test/types/geo_types_05.rs b/tokio-postgres/tests/test/types/geo_types_06.rs similarity index 95% rename from tokio-postgres/tests/test/types/geo_types_05.rs rename to tokio-postgres/tests/test/types/geo_types_06.rs index 334dc0b13..7195abc06 100644 --- a/tokio-postgres/tests/test/types/geo_types_05.rs +++ b/tokio-postgres/tests/test/types/geo_types_06.rs @@ -1,4 +1,4 @@ -use geo_types_05::{Coordinate, LineString, Point, Rect}; +use geo_types_06::{Coordinate, LineString, Point, Rect}; use crate::types::test_type; diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index 9f96019fe..168ca3a4d 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -20,8 +20,8 @@ mod chrono_04; mod eui48_04; #[cfg(feature = "with-geo-types-0_4")] mod geo_types_04; -#[cfg(feature = "with-geo-types-0_5")] -mod geo_types_05; +#[cfg(feature = "with-geo-types-0_6")] +mod geo_types_06; #[cfg(feature = "with-serde_json-1")] mod serde_json_1; #[cfg(feature = "with-time-0_2")] From f5c1902d7d7483744c782d1c3a82fef575ee727a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 24 Jun 2020 13:18:13 +0000 Subject: [PATCH 014/420] Update parking_lot requirement from 0.10 to 0.11 Updates the requirements on [parking_lot](https://github.com/Amanieu/parking_lot) to permit the latest version. - [Release notes](https://github.com/Amanieu/parking_lot/releases) - [Changelog](https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md) - [Commits](https://github.com/Amanieu/parking_lot/compare/0.10.0...0.11.0) Signed-off-by: dependabot-preview[bot] --- tokio-postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index aaed29ae3..b9869b486 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -43,7 +43,7 @@ byteorder = "1.0" fallible-iterator = "0.2" futures = "0.3" log = "0.4" -parking_lot = "0.10" +parking_lot = "0.11" percent-encoding = "2.0" pin-project-lite = "0.1" phf = "0.8" From fe904154df5c68ee7df9c0e9d8be279e935aff81 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 3 Jul 2020 15:16:54 -0400 Subject: [PATCH 015/420] Release postgres-types v0.1.2 --- postgres-types/CHANGELOG.md | 6 ++++++ postgres-types/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index f12c5c7f6..ddbdc6844 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.1.2 - 2020-07-03 + +### Added + +* Added support for `geo-types` 0.6. + ## v0.1.1 - 2020-03-05 ### Added diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index afda3093d..5295f7225 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-types" -version = "0.1.1" +version = "0.1.2" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From 170c5a5e13230a2c7696362be12476079bc5d282 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 3 Jul 2020 15:19:15 -0400 Subject: [PATCH 016/420] Release tokio-postgres v0.5.5 --- tokio-postgres/CHANGELOG.md | 8 +++++++- tokio-postgres/Cargo.toml | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index de25e5616..a02c461a5 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log -## v0.5.4- 2020-05-01 +## v0.5.5 - 2020-07-03 + +### Added + +* Added support for `geo-types` 0.6. + +## v0.5.4 - 2020-05-01 ### Added diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 6ab4f67be..dfc9bb0a9 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.5.4" +version = "0.5.5" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -48,7 +48,7 @@ percent-encoding = "2.0" pin-project-lite = "0.1" phf = "0.8" postgres-protocol = { version = "0.5.0", path = "../postgres-protocol" } -postgres-types = { version = "0.1.1", path = "../postgres-types" } +postgres-types = { version = "0.1.2", path = "../postgres-types" } tokio = { version = "0.2", features = ["io-util"] } tokio-util = { version = "0.3", features = ["codec"] } From 27b36f53e293c4bceba395870056af0dc27b6799 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 3 Jul 2020 15:23:33 -0400 Subject: [PATCH 017/420] Release postgres v0.17.3 --- postgres/CHANGELOG.md | 8 +++++++- postgres/Cargo.toml | 4 ++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index d951ed445..a3ef16cb5 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,10 +1,16 @@ # Change Log +## v0.17.4 - 2020-07-03 + +### Added + +* Added support for `geo-types` 0.6. + ## v0.17.3 - 2020-05-01 ### Fixed -* Errors sent by the server will now be returned from `Client` methods rather than just being logs. +* Errors sent by the server will now be returned from `Client` methods rather than just being logged. ### Added diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index cd199e27f..2b8a7fbd9 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.17.3" +version = "0.17.4" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -34,7 +34,7 @@ with-time-0_2 = ["tokio-postgres/with-time-0_2"] bytes = "0.5" fallible-iterator = "0.2" futures = "0.3" -tokio-postgres = { version = "0.5.4", path = "../tokio-postgres" } +tokio-postgres = { version = "0.5.5", path = "../tokio-postgres" } tokio = { version = "0.2", features = ["rt-core", "time"] } log = "0.4" From 90f763b968143c02dfe035fc4f1e8f0835b11349 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 6 Jul 2020 16:30:43 -0400 Subject: [PATCH 018/420] Release postgres-protocol v0.5.2 --- postgres-protocol/CHANGELOG.md | 6 ++++++ postgres-protocol/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres-protocol/CHANGELOG.md b/postgres-protocol/CHANGELOG.md index b099c1ffa..3cff60c51 100644 --- a/postgres-protocol/CHANGELOG.md +++ b/postgres-protocol/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.5.2 - 2020-07-06 + +### Changed + +* Upgraded `hmac` and `sha2`. + ## v0.5.1 - 2020-03-17 ### Changed diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index d7be8eb80..6c26ac880 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-protocol" -version = "0.5.1" +version = "0.5.2" authors = ["Steven Fackler "] edition = "2018" description = "Low level Postgres protocol APIs" From c9a21f839813c7f963bbfd48e43e9b127629c184 Mon Sep 17 00:00:00 2001 From: shelvacu Date: Mon, 13 Jul 2020 15:15:34 -0700 Subject: [PATCH 019/420] Add Debug and Clone to `AsyncMessage` --- tokio-postgres/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 3b96f4a0e..c69fff793 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -220,6 +220,7 @@ impl Notification { /// An asynchronous message from the server. #[allow(clippy::large_enum_variant)] +#[derive(Debug, Clone)] #[non_exhaustive] pub enum AsyncMessage { /// A notice. From a4a68d543ddd064da706aa5d8b3f0e856330a80b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 19 Jul 2020 13:24:46 -0600 Subject: [PATCH 020/420] Ensure transactions roll back immediately on drop Closes #635 --- postgres/src/test.rs | 25 ++++++++++ postgres/src/transaction.rs | 91 +++++++++++++++++++++++-------------- 2 files changed, 83 insertions(+), 33 deletions(-) diff --git a/postgres/src/test.rs b/postgres/src/test.rs index 6750118ba..35a6a0c79 100644 --- a/postgres/src/test.rs +++ b/postgres/src/test.rs @@ -100,6 +100,31 @@ fn transaction_drop() { assert_eq!(rows.len(), 0); } +#[test] +fn transaction_drop_immediate_rollback() { + let mut client = Client::connect("host=localhost port=5433 user=postgres", NoTls).unwrap(); + let mut client2 = Client::connect("host=localhost port=5433 user=postgres", NoTls).unwrap(); + + client + .simple_query("CREATE TABLE IF NOT EXISTS foo (id SERIAL PRIMARY KEY)") + .unwrap(); + + client + .execute("INSERT INTO foo VALUES (1) ON CONFLICT DO NOTHING", &[]) + .unwrap(); + + let mut transaction = client.transaction().unwrap(); + + transaction + .execute("SELECT * FROM foo FOR UPDATE", &[]) + .unwrap(); + + drop(transaction); + + let rows = client2.query("SELECT * FROM foo FOR UPDATE", &[]).unwrap(); + assert_eq!(rows.len(), 1); +} + #[test] fn nested_transactions() { let mut client = Client::connect("host=localhost port=5433 user=postgres", NoTls).unwrap(); diff --git a/postgres/src/transaction.rs b/postgres/src/transaction.rs index 1a021cd0a..3213b7c1f 100644 --- a/postgres/src/transaction.rs +++ b/postgres/src/transaction.rs @@ -9,7 +9,15 @@ use tokio_postgres::{Error, Row, SimpleQueryMessage}; /// in the transaction. Transactions can be nested, with inner transactions implemented via savepoints. pub struct Transaction<'a> { connection: ConnectionRef<'a>, - transaction: tokio_postgres::Transaction<'a>, + transaction: Option>, +} + +impl<'a> Drop for Transaction<'a> { + fn drop(&mut self) { + if let Some(transaction) = self.transaction.take() { + let _ = self.connection.block_on(transaction.rollback()); + } + } } impl<'a> Transaction<'a> { @@ -19,31 +27,38 @@ impl<'a> Transaction<'a> { ) -> Transaction<'a> { Transaction { connection, - transaction, + transaction: Some(transaction), } } /// Consumes the transaction, committing all changes made within it. pub fn commit(mut self) -> Result<(), Error> { - self.connection.block_on(self.transaction.commit()) + self.connection + .block_on(self.transaction.take().unwrap().commit()) } /// Rolls the transaction back, discarding all changes made within it. /// /// This is equivalent to `Transaction`'s `Drop` implementation, but provides any error encountered to the caller. pub fn rollback(mut self) -> Result<(), Error> { - self.connection.block_on(self.transaction.rollback()) + self.connection + .block_on(self.transaction.take().unwrap().rollback()) } /// Like `Client::prepare`. pub fn prepare(&mut self, query: &str) -> Result { - self.connection.block_on(self.transaction.prepare(query)) + self.connection + .block_on(self.transaction.as_ref().unwrap().prepare(query)) } /// Like `Client::prepare_typed`. pub fn prepare_typed(&mut self, query: &str, types: &[Type]) -> Result { - self.connection - .block_on(self.transaction.prepare_typed(query, types)) + self.connection.block_on( + self.transaction + .as_ref() + .unwrap() + .prepare_typed(query, types), + ) } /// Like `Client::execute`. @@ -52,7 +67,7 @@ impl<'a> Transaction<'a> { T: ?Sized + ToStatement, { self.connection - .block_on(self.transaction.execute(query, params)) + .block_on(self.transaction.as_ref().unwrap().execute(query, params)) } /// Like `Client::query`. @@ -61,7 +76,7 @@ impl<'a> Transaction<'a> { T: ?Sized + ToStatement, { self.connection - .block_on(self.transaction.query(query, params)) + .block_on(self.transaction.as_ref().unwrap().query(query, params)) } /// Like `Client::query_one`. @@ -70,7 +85,7 @@ impl<'a> Transaction<'a> { T: ?Sized + ToStatement, { self.connection - .block_on(self.transaction.query_one(query, params)) + .block_on(self.transaction.as_ref().unwrap().query_one(query, params)) } /// Like `Client::query_opt`. @@ -83,7 +98,7 @@ impl<'a> Transaction<'a> { T: ?Sized + ToStatement, { self.connection - .block_on(self.transaction.query_opt(query, params)) + .block_on(self.transaction.as_ref().unwrap().query_opt(query, params)) } /// Like `Client::query_raw`. @@ -95,7 +110,7 @@ impl<'a> Transaction<'a> { { let stream = self .connection - .block_on(self.transaction.query_raw(query, params))?; + .block_on(self.transaction.as_ref().unwrap().query_raw(query, params))?; Ok(RowIter::new(self.connection.as_ref(), stream)) } @@ -114,7 +129,7 @@ impl<'a> Transaction<'a> { T: ?Sized + ToStatement, { self.connection - .block_on(self.transaction.bind(query, params)) + .block_on(self.transaction.as_ref().unwrap().bind(query, params)) } /// Continues execution of a portal, returning the next set of rows. @@ -122,8 +137,12 @@ impl<'a> Transaction<'a> { /// Unlike `query`, portals can be incrementally evaluated by limiting the number of rows returned in each call to /// `query_portal`. If the requested number is negative or 0, all remaining rows will be returned. pub fn query_portal(&mut self, portal: &Portal, max_rows: i32) -> Result, Error> { - self.connection - .block_on(self.transaction.query_portal(portal, max_rows)) + self.connection.block_on( + self.transaction + .as_ref() + .unwrap() + .query_portal(portal, max_rows), + ) } /// The maximally flexible version of `query_portal`. @@ -132,9 +151,12 @@ impl<'a> Transaction<'a> { portal: &Portal, max_rows: i32, ) -> Result, Error> { - let stream = self - .connection - .block_on(self.transaction.query_portal_raw(portal, max_rows))?; + let stream = self.connection.block_on( + self.transaction + .as_ref() + .unwrap() + .query_portal_raw(portal, max_rows), + )?; Ok(RowIter::new(self.connection.as_ref(), stream)) } @@ -143,7 +165,9 @@ impl<'a> Transaction<'a> { where T: ?Sized + ToStatement, { - let sink = self.connection.block_on(self.transaction.copy_in(query))?; + let sink = self + .connection + .block_on(self.transaction.as_ref().unwrap().copy_in(query))?; Ok(CopyInWriter::new(self.connection.as_ref(), sink)) } @@ -152,44 +176,45 @@ impl<'a> Transaction<'a> { where T: ?Sized + ToStatement, { - let stream = self.connection.block_on(self.transaction.copy_out(query))?; + let stream = self + .connection + .block_on(self.transaction.as_ref().unwrap().copy_out(query))?; Ok(CopyOutReader::new(self.connection.as_ref(), stream)) } /// Like `Client::simple_query`. pub fn simple_query(&mut self, query: &str) -> Result, Error> { self.connection - .block_on(self.transaction.simple_query(query)) + .block_on(self.transaction.as_ref().unwrap().simple_query(query)) } /// Like `Client::batch_execute`. pub fn batch_execute(&mut self, query: &str) -> Result<(), Error> { self.connection - .block_on(self.transaction.batch_execute(query)) + .block_on(self.transaction.as_ref().unwrap().batch_execute(query)) } /// Like `Client::cancel_token`. pub fn cancel_token(&self) -> CancelToken { - CancelToken::new(self.transaction.cancel_token()) + CancelToken::new(self.transaction.as_ref().unwrap().cancel_token()) } /// Like `Client::transaction`, but creates a nested transaction via a savepoint. pub fn transaction(&mut self) -> Result, Error> { - let transaction = self.connection.block_on(self.transaction.transaction())?; - Ok(Transaction { - connection: self.connection.as_ref(), - transaction, - }) + let transaction = self + .connection + .block_on(self.transaction.as_mut().unwrap().transaction())?; + Ok(Transaction::new(self.connection.as_ref(), transaction)) } + /// Like `Client::transaction`, but creates a nested transaction via a savepoint with the specified name. pub fn savepoint(&mut self, name: I) -> Result, Error> where I: Into, { - let transaction = self.connection.block_on(self.transaction.savepoint(name))?; - Ok(Transaction { - connection: self.connection.as_ref(), - transaction, - }) + let transaction = self + .connection + .block_on(self.transaction.as_mut().unwrap().savepoint(name))?; + Ok(Transaction::new(self.connection.as_ref(), transaction)) } } From f6620e6a24ac416101a811b89b69cd74e137af51 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 19 Jul 2020 13:27:27 -0600 Subject: [PATCH 021/420] Release postgres v0.17.5 --- postgres/CHANGELOG.md | 6 ++++++ postgres/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index a3ef16cb5..965bd2b09 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.17.5 - 2020-07-19 + +### Fixed + +* Fixed transactions to roll back immediately on drop. + ## v0.17.4 - 2020-07-03 ### Added diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 2b8a7fbd9..3652ac35d 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.17.4" +version = "0.17.5" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From bc682b3103f9a03e4ee1af8881d826f4bffcbf44 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 27 Jul 2020 21:42:02 -0400 Subject: [PATCH 022/420] Explicitly terminate the connection in sync API Closes #613 --- postgres/src/client.rs | 27 +++++++++++++++++++++++++++ postgres/src/test.rs | 6 ++++++ tokio-postgres/src/client.rs | 5 +++++ 3 files changed, 38 insertions(+) diff --git a/postgres/src/client.rs b/postgres/src/client.rs index a0c61b33d..dcb9c72d4 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -3,6 +3,7 @@ use crate::{ CancelToken, Config, CopyInWriter, CopyOutReader, Notifications, RowIter, Statement, ToStatement, Transaction, TransactionBuilder, }; +use std::task::Poll; use tokio_postgres::tls::{MakeTlsConnect, TlsConnect}; use tokio_postgres::types::{ToSql, Type}; use tokio_postgres::{Error, Row, SimpleQueryMessage, Socket}; @@ -13,6 +14,12 @@ pub struct Client { client: tokio_postgres::Client, } +impl Drop for Client { + fn drop(&mut self) { + let _ = self.close_inner(); + } +} + impl Client { pub(crate) fn new(connection: Connection, client: tokio_postgres::Client) -> Client { Client { connection, client } @@ -524,4 +531,24 @@ impl Client { pub fn is_closed(&self) -> bool { self.client.is_closed() } + + /// Closes the client's connection to the server. + /// + /// This is equivalent to `Client`'s `Drop` implementation, except that it returns any error encountered to the + /// caller. + pub fn close(mut self) -> Result<(), Error> { + self.close_inner() + } + + fn close_inner(&mut self) -> Result<(), Error> { + self.client.__private_api_close(); + + self.connection.poll_block_on(|_, _, done| { + if done { + Poll::Ready(Ok(())) + } else { + Poll::Pending + } + }) + } } diff --git a/postgres/src/test.rs b/postgres/src/test.rs index 35a6a0c79..557013746 100644 --- a/postgres/src/test.rs +++ b/postgres/src/test.rs @@ -475,3 +475,9 @@ fn notifications_timeout_iter() { assert_eq!(notifications[0].payload(), "hello"); assert_eq!(notifications[1].payload(), "world"); } + +#[test] +fn explicit_close() { + let client = Client::connect("host=localhost port=5433 user=postgres", NoTls).unwrap(); + client.close().unwrap(); +} diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 2d9b79728..e19caae83 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -529,6 +529,11 @@ impl Client { pub fn is_closed(&self) -> bool { self.inner.sender.is_closed() } + + #[doc(hidden)] + pub fn __private_api_close(&mut self) { + self.inner.sender.close_channel() + } } impl fmt::Debug for Client { From a30f0b6c0586e467cd48d759b903eb8d4ec7c3e7 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Thu, 30 Jul 2020 22:51:18 -0400 Subject: [PATCH 023/420] Use checked arithmetic when decoding into chrono types This avoids an overflow panic if the timestamp is the special "infinity" or "-infinity" value and produces an error instead. Fix #640. --- postgres-types/src/chrono_04.rs | 9 +++-- tokio-postgres/tests/test/types/chrono_04.rs | 35 +++++++++++++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/postgres-types/src/chrono_04.rs b/postgres-types/src/chrono_04.rs index 9bfbb786f..fcd25e6d1 100644 --- a/postgres-types/src/chrono_04.rs +++ b/postgres-types/src/chrono_04.rs @@ -12,7 +12,9 @@ fn base() -> NaiveDateTime { impl<'a> FromSql<'a> for NaiveDateTime { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let t = types::timestamp_from_sql(raw)?; - Ok(base() + Duration::microseconds(t)) + base() + .checked_add_signed(Duration::microseconds(t)) + .ok_or_else(|| "value too large to decode".into()) } accepts!(TIMESTAMP); @@ -104,7 +106,10 @@ impl ToSql for DateTime { impl<'a> FromSql<'a> for NaiveDate { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let jd = types::date_from_sql(raw)?; - Ok(base().date() + Duration::days(i64::from(jd))) + base() + .date() + .checked_add_signed(Duration::days(i64::from(jd))) + .ok_or_else(|| "value too large to decode".into()) } accepts!(DATE); diff --git a/tokio-postgres/tests/test/types/chrono_04.rs b/tokio-postgres/tests/test/types/chrono_04.rs index 13c8dc14f..a8e9e5afa 100644 --- a/tokio-postgres/tests/test/types/chrono_04.rs +++ b/tokio-postgres/tests/test/types/chrono_04.rs @@ -1,6 +1,9 @@ use chrono_04::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc}; -use tokio_postgres::types::{Date, Timestamp}; +use std::fmt; +use tokio_postgres::types::{Date, FromSqlOwned, Timestamp}; +use tokio_postgres::Client; +use crate::connect; use crate::types::test_type; #[tokio::test] @@ -153,3 +156,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 = 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 ce7ce310b91bd24d80bd98c4e267d2b14ae4220c Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Fri, 31 Jul 2020 20:59:57 -0400 Subject: [PATCH 024/420] Give a more helpful message on error Before: ``` database error: ERROR: insert or update on table "owner_rels" violates foreign key constraint "owner_rels_cid_fkey" ``` After: ``` database error: ERROR: insert or update on table "owner_rels" violates foreign key constraint "owner_rels_cid_fkey" DETAIL: Key (cid)=(4) is not present in table "releases". ``` --- tokio-postgres/src/error/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tokio-postgres/src/error/mod.rs b/tokio-postgres/src/error/mod.rs index 0bcf0c6f9..8a59109a8 100644 --- a/tokio-postgres/src/error/mod.rs +++ b/tokio-postgres/src/error/mod.rs @@ -309,7 +309,14 @@ impl DbError { impl fmt::Display for DbError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(fmt, "{}: {}", self.severity, self.message) + write!(fmt, "{}: {}", self.severity, self.message)?; + if let Some(detail) = &self.detail { + write!(fmt, "DETAIL: {}", detail)?; + } + if let Some(hint) = &self.hint { + write!(fmt, "HINT: {}", hint)?; + } + Ok(()) } } From 61f6e3e5c49390ab43035a222f67976814525e41 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 1 Aug 2020 11:12:22 -0400 Subject: [PATCH 025/420] Add newline before DETAIL and HINT --- tokio-postgres/src/error/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/src/error/mod.rs b/tokio-postgres/src/error/mod.rs index 8a59109a8..f9335cfe7 100644 --- a/tokio-postgres/src/error/mod.rs +++ b/tokio-postgres/src/error/mod.rs @@ -311,10 +311,10 @@ impl fmt::Display for DbError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "{}: {}", self.severity, self.message)?; if let Some(detail) = &self.detail { - write!(fmt, "DETAIL: {}", detail)?; + write!(fmt, "\nDETAIL: {}", detail)?; } if let Some(hint) = &self.hint { - write!(fmt, "HINT: {}", hint)?; + write!(fmt, "\nHINT: {}", hint)?; } Ok(()) } From 26d7b38b039e8f0af3b26718f0ebf80b60bc9102 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 12 Aug 2020 13:17:41 +0000 Subject: [PATCH 026/420] Update hmac requirement from 0.8 to 0.9 Updates the requirements on [hmac](https://github.com/RustCrypto/MACs) to permit the latest version. - [Release notes](https://github.com/RustCrypto/MACs/releases) - [Commits](https://github.com/RustCrypto/MACs/compare/hmac-v0.8.0...hmac-v0.9.0) Signed-off-by: dependabot-preview[bot] --- 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 6c26ac880..400956c18 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -13,7 +13,7 @@ base64 = "0.12" byteorder = "1.0" bytes = "0.5" fallible-iterator = "0.2" -hmac = "0.8" +hmac = "0.9" md5 = "0.7" memchr = "2.0" rand = "0.7" From 391a54aea1afb3e333270b8532c351d70a9c4bd4 Mon Sep 17 00:00:00 2001 From: Juan Aguilar Santillana Date: Sun, 20 Sep 2020 10:37:15 +0000 Subject: [PATCH 027/420] Avoiding get reference of a u16 --- tokio-postgres/src/connect.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index db2ddc85f..2cfc9c6e1 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -25,11 +25,12 @@ where let mut error = None; for (i, host) in config.host.iter().enumerate() { - let port = *config + let port = config .port .get(i) .or_else(|| config.port.get(0)) - .unwrap_or(&5432); + .copied() + .unwrap_or(5432); let hostname = match host { Host::Tcp(host) => &**host, From a2ca75e9c46ac40510572f84790d25f686755453 Mon Sep 17 00:00:00 2001 From: Juan Aguilar Santillana Date: Sun, 20 Sep 2020 10:43:22 +0000 Subject: [PATCH 028/420] Prettify `host` cast as str --- tokio-postgres/src/connect.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 2cfc9c6e1..f529ddbbb 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -33,7 +33,7 @@ where .unwrap_or(5432); let hostname = match host { - Host::Tcp(host) => &**host, + Host::Tcp(host) => host.as_str(), // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter #[cfg(unix)] Host::Unix(_) => "", From 4af6fcd911227f1d3cf0ea93d8d7ea0c34fb1195 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Wed, 16 Sep 2020 02:43:34 -0400 Subject: [PATCH 029/420] Permit configuring the notice callback Right now the behavior is hardcoded to log any received notices at the info level. Add a `notice_callback` configuration option that permits installing an arbitrary callback to handle any received notices. As discussed in #588. --- postgres/src/config.rs | 36 +++++++++++++++++++++++++++++++----- postgres/src/connection.rs | 14 +++++++++++--- postgres/src/test.rs | 18 ++++++++++++++++++ 3 files changed, 60 insertions(+), 8 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index b344efdd2..b4d01b1d5 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -4,13 +4,16 @@ use crate::connection::Connection; use crate::Client; +use log::info; use std::fmt; use std::path::Path; use std::str::FromStr; +use std::sync::Arc; use std::time::Duration; use tokio::runtime; #[doc(inline)] pub use tokio_postgres::config::{ChannelBinding, Host, SslMode, TargetSessionAttrs}; +use tokio_postgres::error::DbError; use tokio_postgres::tls::{MakeTlsConnect, TlsConnect}; use tokio_postgres::{Error, Socket}; @@ -90,6 +93,7 @@ use tokio_postgres::{Error, Socket}; #[derive(Clone)] pub struct Config { config: tokio_postgres::Config, + notice_callback: Arc, } impl fmt::Debug for Config { @@ -109,9 +113,7 @@ impl Default for Config { impl Config { /// Creates a new configuration. pub fn new() -> Config { - Config { - config: tokio_postgres::Config::new(), - } + tokio_postgres::Config::new().into() } /// Sets the user to authenticate with. @@ -307,6 +309,25 @@ impl Config { self.config.get_channel_binding() } + /// Sets the notice callback. + /// + /// This callback will be invoked with the contents of every + /// [`AsyncMessage::Notice`] that is received by the connection. Notices use + /// the same structure as errors, but they are not "errors" per-se. + /// + /// Notices are distinct from notifications, which are instead accessible + /// via the [`Notifications`] API. + /// + /// [`AsyncMessage::Notice`]: tokio_postgres::AsyncMessage::Notice + /// [`Notifications`]: crate::Notifications + pub fn notice_callback(&mut self, f: F) -> &mut Config + where + F: Fn(DbError) + Send + Sync + 'static, + { + self.notice_callback = Arc::new(f); + self + } + /// Opens a connection to a PostgreSQL database. pub fn connect(&self, tls: T) -> Result where @@ -323,7 +344,7 @@ impl Config { let (client, connection) = runtime.block_on(self.config.connect(tls))?; - let connection = Connection::new(runtime, connection); + let connection = Connection::new(runtime, connection, self.notice_callback.clone()); Ok(Client::new(connection, client)) } } @@ -338,6 +359,11 @@ impl FromStr for Config { impl From for Config { fn from(config: tokio_postgres::Config) -> Config { - Config { config } + Config { + config, + notice_callback: Arc::new(|notice| { + info!("{}: {}", notice.severity(), notice.message()) + }), + } } } diff --git a/postgres/src/connection.rs b/postgres/src/connection.rs index acea5eca7..a6abb7278 100644 --- a/postgres/src/connection.rs +++ b/postgres/src/connection.rs @@ -1,24 +1,30 @@ use crate::{Error, Notification}; use futures::future; use futures::{pin_mut, Stream}; -use log::info; use std::collections::VecDeque; use std::future::Future; use std::ops::{Deref, DerefMut}; use std::pin::Pin; +use std::sync::Arc; use std::task::{Context, Poll}; use tokio::io::{AsyncRead, AsyncWrite}; use tokio::runtime::Runtime; +use tokio_postgres::error::DbError; use tokio_postgres::AsyncMessage; pub struct Connection { runtime: Runtime, connection: Pin> + Send>>, notifications: VecDeque, + notice_callback: Arc, } impl Connection { - pub fn new(runtime: Runtime, connection: tokio_postgres::Connection) -> Connection + pub fn new( + runtime: Runtime, + connection: tokio_postgres::Connection, + notice_callback: Arc, + ) -> Connection where S: AsyncRead + AsyncWrite + Unpin + 'static + Send, T: AsyncRead + AsyncWrite + Unpin + 'static + Send, @@ -27,6 +33,7 @@ impl Connection { runtime, connection: Box::pin(ConnectionStream { connection }), notifications: VecDeque::new(), + notice_callback, } } @@ -55,6 +62,7 @@ impl Connection { { let connection = &mut self.connection; let notifications = &mut self.notifications; + let notice_callback = &mut self.notice_callback; self.runtime.block_on({ future::poll_fn(|cx| { let done = loop { @@ -63,7 +71,7 @@ impl Connection { notifications.push_back(notification); } Poll::Ready(Some(Ok(AsyncMessage::Notice(notice)))) => { - info!("{}: {}", notice.severity(), notice.message()); + notice_callback(notice) } Poll::Ready(Some(Ok(_))) => {} Poll::Ready(Some(Err(e))) => return Poll::Ready(Err(e)), diff --git a/postgres/src/test.rs b/postgres/src/test.rs index 557013746..dcf202ef7 100644 --- a/postgres/src/test.rs +++ b/postgres/src/test.rs @@ -1,4 +1,6 @@ use std::io::{Read, Write}; +use std::str::FromStr; +use std::sync::mpsc; use std::thread; use std::time::Duration; use tokio_postgres::error::SqlState; @@ -476,6 +478,22 @@ fn notifications_timeout_iter() { assert_eq!(notifications[1].payload(), "world"); } +#[test] +fn notice_callback() { + let (notice_tx, notice_rx) = mpsc::sync_channel(64); + let mut client = Config::from_str("host=localhost port=5433 user=postgres") + .unwrap() + .notice_callback(move |n| notice_tx.send(n).unwrap()) + .connect(NoTls) + .unwrap(); + + client + .batch_execute("DO $$BEGIN RAISE NOTICE 'custom'; END$$") + .unwrap(); + + assert_eq!(notice_rx.recv().unwrap().message(), "custom"); +} + #[test] fn explicit_close() { let client = Client::connect("host=localhost port=5433 user=postgres", NoTls).unwrap(); From bb961edcc4f150b961497c4509a713b9625f29d6 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Fri, 25 Sep 2020 15:36:51 -0400 Subject: [PATCH 030/420] Disable chrono's "oldtime" feature to drop time v0.1 The latest version of chrono, v0.4.16, permits removing its dependency on the long-deprecated time v0.1 crate by disabling the "oldtime" feature. For backwards compatibility, chrono is leaving the "oldtime" feature on by default, so disabling the "oldtime" feature requires disabling all default features and then re-enabling the one default feature ("clock") that rust-postgres needs. Note that this change does not cause any backwards-compatibility problems for users of rust-postgres. The "oldtime" feature controls only whether `time_v01::Duration` and `chrono::Duration` are the same type and does not affect any of the APIs used by rust-postgres. --- postgres-types/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 5295f7225..b50653168 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -28,7 +28,7 @@ postgres-protocol = { version = "0.5.0", path = "../postgres-protocol" } postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-derive" } bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } -chrono-04 = { version = "0.4", package = "chrono", optional = true } +chrono-04 = { version = "0.4.16", package = "chrono", default-features = false, features = ["clock"], optional = true } eui48-04 = { version = "0.4", package = "eui48", optional = true } geo-types-04 = { version = "0.4", package = "geo-types", optional = true } geo-types-06 = { version = "0.6", package = "geo-types", optional = true } diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index dfc9bb0a9..84cc3bc8a 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -58,7 +58,7 @@ env_logger = "0.7" criterion = "0.3" bit-vec-06 = { version = "0.6", package = "bit-vec" } -chrono-04 = { version = "0.4", package = "chrono" } +chrono-04 = { version = "0.4", package = "chrono", default-features = false } eui48-04 = { version = "0.4", package = "eui48" } geo-types-04 = { version = "0.4", package = "geo-types" } geo-types-06 = { version = "0.6", package = "geo-types" } From 6c506c1c1686b1bf06cd26e0dc43618a743e1b90 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 1 Oct 2020 13:18:42 +0000 Subject: [PATCH 031/420] Update base64 requirement from 0.12 to 0.13 Updates the requirements on [base64](https://github.com/marshallpierce/rust-base64) to permit the latest version. - [Release notes](https://github.com/marshallpierce/rust-base64/releases) - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.12.0...v0.13.0) Signed-off-by: dependabot-preview[bot] --- 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 400956c18..0c89a5724 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/sfackler/rust-postgres" readme = "../README.md" [dependencies] -base64 = "0.12" +base64 = "0.13" byteorder = "1.0" bytes = "0.5" fallible-iterator = "0.2" From aadd90854d2e23e64818bf2e899770f4c3bbde32 Mon Sep 17 00:00:00 2001 From: Dan Burkert Date: Fri, 2 Oct 2020 15:56:42 -0700 Subject: [PATCH 032/420] derive Clone, PartialEq and Eq for postgres_types::Json It's a bit unwieldy using the `Json` type in structs without this. `Json` is 'just data', so I think it's usually appropriate to consider instances to be cloneable and testable for equivalence. --- postgres-types/src/serde_json_1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres-types/src/serde_json_1.rs b/postgres-types/src/serde_json_1.rs index e5183d3f5..e0fecb496 100644 --- a/postgres-types/src/serde_json_1.rs +++ b/postgres-types/src/serde_json_1.rs @@ -8,7 +8,7 @@ use std::fmt::Debug; use std::io::Read; /// A wrapper type to allow arbitrary `Serialize`/`Deserialize` types to convert to Postgres JSON values. -#[derive(Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Json(pub T); impl<'a, T> FromSql<'a> for Json From d1f9d6d8020843dbcd4fa6764b5abf33e56ade33 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 15 Oct 2020 21:14:13 -0400 Subject: [PATCH 033/420] fix clippy --- codegen/src/type_gen.rs | 5 +---- postgres-protocol/src/authentication/sasl.rs | 20 ++++---------------- postgres-types/src/lib.rs | 5 +---- postgres-types/src/special.rs | 10 ++-------- 4 files changed, 8 insertions(+), 32 deletions(-) diff --git a/codegen/src/type_gen.rs b/codegen/src/type_gen.rs index 485442a3f..7e92e062a 100644 --- a/codegen/src/type_gen.rs +++ b/codegen/src/type_gen.rs @@ -136,10 +136,7 @@ impl<'a> DatParser<'a> { fn peek(&mut self, target: char) -> bool { self.skip_ws(); - match self.it.peek() { - Some((_, ch)) if *ch == target => true, - _ => false, - } + matches!(self.it.peek(), Some((_, ch)) if *ch == target) } fn eof(&mut self) { diff --git a/postgres-protocol/src/authentication/sasl.rs b/postgres-protocol/src/authentication/sasl.rs index c99a27a2e..416b4b998 100644 --- a/postgres-protocol/src/authentication/sasl.rs +++ b/postgres-protocol/src/authentication/sasl.rs @@ -330,10 +330,7 @@ impl<'a> Parser<'a> { } fn printable(&mut self) -> io::Result<&'a str> { - self.take_while(|c| match c { - '\x21'..='\x2b' | '\x2d'..='\x7e' => true, - _ => false, - }) + self.take_while(|c| matches!(c, '\x21'..='\x2b' | '\x2d'..='\x7e')) } fn nonce(&mut self) -> io::Result<&'a str> { @@ -343,10 +340,7 @@ impl<'a> Parser<'a> { } fn base64(&mut self) -> io::Result<&'a str> { - self.take_while(|c| match c { - 'a'..='z' | 'A'..='Z' | '0'..='9' | '/' | '+' | '=' => true, - _ => false, - }) + self.take_while(|c| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '/' | '+' | '=')) } fn salt(&mut self) -> io::Result<&'a str> { @@ -356,10 +350,7 @@ impl<'a> Parser<'a> { } fn posit_number(&mut self) -> io::Result { - let n = self.take_while(|c| match c { - '0'..='9' => true, - _ => false, - })?; + let n = self.take_while(|c| matches!(c, '0'..='9'))?; n.parse() .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e)) } @@ -396,10 +387,7 @@ impl<'a> Parser<'a> { } fn value(&mut self) -> io::Result<&'a str> { - self.take_while(|c| match c { - '\0' | '=' | ',' => false, - _ => true, - }) + self.take_while(|c| matches!(c, '\0' | '=' | ',')) } fn server_error(&mut self) -> io::Result> { diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 258b68edc..e9a5846e1 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -144,10 +144,7 @@ const NSEC_PER_USEC: u64 = 1_000; macro_rules! accepts { ($($expected:ident),+) => ( fn accepts(ty: &$crate::Type) -> bool { - match *ty { - $($crate::Type::$expected)|+ => true, - _ => false - } + matches!(*ty, $($crate::Type::$expected)|+) } ) } diff --git a/postgres-types/src/special.rs b/postgres-types/src/special.rs index 5a2d7bc08..8579885ef 100644 --- a/postgres-types/src/special.rs +++ b/postgres-types/src/special.rs @@ -75,10 +75,7 @@ impl<'a, T: FromSql<'a>> FromSql<'a> for Timestamp { } fn accepts(ty: &Type) -> bool { - match *ty { - Type::TIMESTAMP | Type::TIMESTAMPTZ if T::accepts(ty) => true, - _ => false, - } + matches!(*ty, Type::TIMESTAMP | Type::TIMESTAMPTZ if T::accepts(ty)) } } @@ -99,10 +96,7 @@ impl ToSql for Timestamp { } fn accepts(ty: &Type) -> bool { - match *ty { - Type::TIMESTAMP | Type::TIMESTAMPTZ if T::accepts(ty) => true, - _ => false, - } + matches!(*ty, Type::TIMESTAMP | Type::TIMESTAMPTZ if T::accepts(ty)) } to_sql_checked!(); From 74439823688cd7140c507a0950b7dffb12fb2f51 Mon Sep 17 00:00:00 2001 From: wuaoxiang Date: Sat, 17 Oct 2020 11:33:21 +0800 Subject: [PATCH 034/420] Make postgres protocol version value more readable --- postgres-protocol/src/message/frontend.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/postgres-protocol/src/message/frontend.rs b/postgres-protocol/src/message/frontend.rs index 8587cd080..5d0a8ff8c 100644 --- a/postgres-protocol/src/message/frontend.rs +++ b/postgres-protocol/src/message/frontend.rs @@ -260,7 +260,8 @@ where I: IntoIterator, { write_body(buf, |buf| { - buf.put_i32(196_608); + // postgres protocol version 3.0(196608) in bigger-endian + buf.put_i32(0x00_03_00_00); for (key, value) in parameters { write_cstr(key.as_bytes(), buf)?; write_cstr(value.as_bytes(), buf)?; From 2689070d19fbef35f6c61085388cf9bfd6511da5 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 17 Oct 2020 09:49:45 -0400 Subject: [PATCH 035/420] Upgrade to tokio 0.3 --- postgres-native-tls/Cargo.toml | 7 ++-- postgres-native-tls/src/lib.rs | 46 ++++++------------------ postgres-openssl/Cargo.toml | 7 ++-- postgres-openssl/src/lib.rs | 34 ++---------------- postgres/Cargo.toml | 2 +- postgres/src/cancel_token.rs | 3 +- postgres/src/config.rs | 3 +- postgres/src/connection.rs | 3 +- postgres/src/notifications.rs | 6 ++-- tokio-postgres/Cargo.toml | 8 ++--- tokio-postgres/benches/bench.rs | 8 ++--- tokio-postgres/src/connect_socket.rs | 10 ++---- tokio-postgres/src/maybe_tls_stream.rs | 45 ++---------------------- tokio-postgres/src/socket.rs | 48 ++------------------------ tokio-postgres/src/tls.rs | 6 ++-- tokio-postgres/tests/test/main.rs | 2 +- tokio-postgres/tests/test/runtime.rs | 2 +- 17 files changed, 49 insertions(+), 191 deletions(-) diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index e2d60d1fa..51145bf95 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -16,13 +16,12 @@ default = ["runtime"] runtime = ["tokio-postgres/runtime"] [dependencies] -bytes = "0.5" futures = "0.3" native-tls = "0.2" -tokio = "0.2" -tokio-tls = "0.3" +tokio = "0.3" +tokio-native-tls = "0.2" tokio-postgres = { version = "0.5.0", path = "../tokio-postgres", default-features = false } [dev-dependencies] -tokio = { version = "0.2", features = ["full"] } +tokio = { version = "0.3", features = ["full"] } postgres = { version = "0.17.0", path = "../postgres" } diff --git a/postgres-native-tls/src/lib.rs b/postgres-native-tls/src/lib.rs index 207ae6cb2..00413c27b 100644 --- a/postgres-native-tls/src/lib.rs +++ b/postgres-native-tls/src/lib.rs @@ -48,13 +48,11 @@ #![doc(html_root_url = "https://docs.rs/postgres-native-tls/0.3")] #![warn(rust_2018_idioms, clippy::all, missing_docs)] -use bytes::{Buf, BufMut}; use std::future::Future; use std::io; -use std::mem::MaybeUninit; use std::pin::Pin; use std::task::{Context, Poll}; -use tokio::io::{AsyncRead, AsyncWrite}; +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_postgres::tls; #[cfg(feature = "runtime")] use tokio_postgres::tls::MakeTlsConnect; @@ -94,7 +92,7 @@ where /// A `TlsConnect` implementation using the `native-tls` crate. pub struct TlsConnector { - connector: tokio_tls::TlsConnector, + connector: tokio_native_tls::TlsConnector, domain: String, } @@ -102,7 +100,7 @@ impl TlsConnector { /// Creates a new connector configured to connect to the specified domain. pub fn new(connector: native_tls::TlsConnector, domain: &str) -> TlsConnector { TlsConnector { - connector: tokio_tls::TlsConnector::from(connector), + connector: tokio_native_tls::TlsConnector::from(connector), domain: domain.to_string(), } } @@ -129,34 +127,19 @@ where } /// The stream returned by `TlsConnector`. -pub struct TlsStream(tokio_tls::TlsStream); +pub struct TlsStream(tokio_native_tls::TlsStream); impl AsyncRead for TlsStream where S: AsyncRead + AsyncWrite + Unpin, { - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [MaybeUninit]) -> bool { - self.0.prepare_uninitialized_buffer(buf) - } - fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { + buf: &mut ReadBuf<'_>, + ) -> Poll> { Pin::new(&mut self.0).poll_read(cx, buf) } - - fn poll_read_buf( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut B, - ) -> Poll> - where - Self: Sized, - { - Pin::new(&mut self.0).poll_read_buf(cx, buf) - } } impl AsyncWrite for TlsStream @@ -178,17 +161,6 @@ where fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { Pin::new(&mut self.0).poll_shutdown(cx) } - - fn poll_write_buf( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut B, - ) -> Poll> - where - Self: Sized, - { - Pin::new(&mut self.0).poll_write_buf(cx, buf) - } } impl tls::TlsStream for TlsStream @@ -196,7 +168,9 @@ where S: AsyncRead + AsyncWrite + Unpin, { fn channel_binding(&self) -> ChannelBinding { - // FIXME https://github.com/tokio-rs/tokio/issues/1383 - ChannelBinding::none() + match self.0.get_ref().tls_server_end_point().ok().flatten() { + Some(buf) => ChannelBinding::tls_server_end_point(buf), + None => ChannelBinding::none(), + } } } diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index a3c9f65fa..e022a4f8a 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -16,13 +16,12 @@ default = ["runtime"] runtime = ["tokio-postgres/runtime"] [dependencies] -bytes = "0.5" futures = "0.3" openssl = "0.10" -tokio = "0.2" -tokio-openssl = "0.4" +tokio = "0.3" +tokio-openssl = "0.5" tokio-postgres = { version = "0.5.0", path = "../tokio-postgres", default-features = false } [dev-dependencies] -tokio = { version = "0.2", features = ["full"] } +tokio = { version = "0.3", features = ["full"] } postgres = { version = "0.17.0", path = "../postgres" } diff --git a/postgres-openssl/src/lib.rs b/postgres-openssl/src/lib.rs index 23a653c60..3780f2082 100644 --- a/postgres-openssl/src/lib.rs +++ b/postgres-openssl/src/lib.rs @@ -42,7 +42,6 @@ #![doc(html_root_url = "https://docs.rs/postgres-openssl/0.3")] #![warn(rust_2018_idioms, clippy::all, missing_docs)] -use bytes::{Buf, BufMut}; #[cfg(feature = "runtime")] use openssl::error::ErrorStack; use openssl::hash::MessageDigest; @@ -53,12 +52,11 @@ use openssl::ssl::{ConnectConfiguration, SslRef}; use std::fmt::Debug; use std::future::Future; use std::io; -use std::mem::MaybeUninit; use std::pin::Pin; #[cfg(feature = "runtime")] use std::sync::Arc; use std::task::{Context, Poll}; -use tokio::io::{AsyncRead, AsyncWrite}; +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio_openssl::{HandshakeError, SslStream}; use tokio_postgres::tls; #[cfg(feature = "runtime")] @@ -157,28 +155,13 @@ impl AsyncRead for TlsStream where S: AsyncRead + AsyncWrite + Unpin, { - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [MaybeUninit]) -> bool { - self.0.prepare_uninitialized_buffer(buf) - } - fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { + buf: &mut ReadBuf<'_>, + ) -> Poll> { Pin::new(&mut self.0).poll_read(cx, buf) } - - fn poll_read_buf( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut B, - ) -> Poll> - where - Self: Sized, - { - Pin::new(&mut self.0).poll_read_buf(cx, buf) - } } impl AsyncWrite for TlsStream @@ -200,17 +183,6 @@ where fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { Pin::new(&mut self.0).poll_shutdown(cx) } - - fn poll_write_buf( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut B, - ) -> Poll> - where - Self: Sized, - { - Pin::new(&mut self.0).poll_write_buf(cx, buf) - } } impl tls::TlsStream for TlsStream diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 3652ac35d..db9104453 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -36,7 +36,7 @@ fallible-iterator = "0.2" futures = "0.3" tokio-postgres = { version = "0.5.5", path = "../tokio-postgres" } -tokio = { version = "0.2", features = ["rt-core", "time"] } +tokio = { version = "0.3", features = ["rt", "time"] } log = "0.4" [dev-dependencies] diff --git a/postgres/src/cancel_token.rs b/postgres/src/cancel_token.rs index f140e60e2..be24edcc8 100644 --- a/postgres/src/cancel_token.rs +++ b/postgres/src/cancel_token.rs @@ -26,9 +26,8 @@ impl CancelToken { where T: MakeTlsConnect, { - runtime::Builder::new() + runtime::Builder::new_current_thread() .enable_all() - .basic_scheduler() .build() .unwrap() // FIXME don't unwrap .block_on(self.0.cancel_query(tls)) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index b4d01b1d5..249e6b44e 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -336,9 +336,8 @@ impl Config { T::Stream: Send, >::Future: Send, { - let mut runtime = runtime::Builder::new() + let runtime = runtime::Builder::new_current_thread() .enable_all() - .basic_scheduler() .build() .unwrap(); // FIXME don't unwrap diff --git a/postgres/src/connection.rs b/postgres/src/connection.rs index a6abb7278..bc8564f54 100644 --- a/postgres/src/connection.rs +++ b/postgres/src/connection.rs @@ -45,7 +45,8 @@ impl Connection { where F: FnOnce() -> T, { - self.runtime.enter(f) + let _guard = self.runtime.enter(); + f() } pub fn block_on(&mut self, future: F) -> Result diff --git a/postgres/src/notifications.rs b/postgres/src/notifications.rs index e8c681548..241c95a5d 100644 --- a/postgres/src/notifications.rs +++ b/postgres/src/notifications.rs @@ -6,7 +6,7 @@ use fallible_iterator::FallibleIterator; use futures::{ready, FutureExt}; use std::task::Poll; use std::time::Duration; -use tokio::time::{self, Delay, Instant}; +use tokio::time::{self, Instant, Sleep}; /// Notifications from a PostgreSQL backend. pub struct Notifications<'a> { @@ -64,7 +64,7 @@ impl<'a> Notifications<'a> { /// This iterator may start returning `Some` after previously returning `None` if more notifications are received. pub fn timeout_iter(&mut self, timeout: Duration) -> TimeoutIter<'_> { TimeoutIter { - delay: self.connection.enter(|| time::delay_for(timeout)), + delay: self.connection.enter(|| time::sleep(timeout)), timeout, connection: self.connection.as_ref(), } @@ -124,7 +124,7 @@ impl<'a> FallibleIterator for BlockingIter<'a> { /// A time-limited blocking iterator over pending notifications. pub struct TimeoutIter<'a> { connection: ConnectionRef<'a>, - delay: Delay, + delay: Sleep, timeout: Duration, } diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 84cc3bc8a..aea6aa5ca 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -25,7 +25,7 @@ circle-ci = { repository = "sfackler/rust-postgres" } [features] default = ["runtime"] -runtime = ["tokio/dns", "tokio/net", "tokio/time"] +runtime = ["tokio/net", "tokio/time"] with-bit-vec-0_6 = ["postgres-types/with-bit-vec-0_6"] with-chrono-0_4 = ["postgres-types/with-chrono-0_4"] @@ -49,11 +49,11 @@ pin-project-lite = "0.1" phf = "0.8" postgres-protocol = { version = "0.5.0", path = "../postgres-protocol" } postgres-types = { version = "0.1.2", path = "../postgres-types" } -tokio = { version = "0.2", features = ["io-util"] } -tokio-util = { version = "0.3", features = ["codec"] } +tokio = { version = "0.3", features = ["io-util"] } +tokio-util = { version = "0.4", features = ["codec"] } [dev-dependencies] -tokio = { version = "0.2", features = ["full"] } +tokio = { version = "0.3", features = ["full"] } env_logger = "0.7" criterion = "0.3" diff --git a/tokio-postgres/benches/bench.rs b/tokio-postgres/benches/bench.rs index 315bea8e4..fececa2b5 100644 --- a/tokio-postgres/benches/bench.rs +++ b/tokio-postgres/benches/bench.rs @@ -7,7 +7,7 @@ use tokio::runtime::Runtime; use tokio_postgres::{Client, NoTls}; fn setup() -> (Client, Runtime) { - let mut runtime = Runtime::new().unwrap(); + let runtime = Runtime::new().unwrap(); let (client, conn) = runtime .block_on(tokio_postgres::connect( "host=localhost port=5433 user=postgres", @@ -19,7 +19,7 @@ fn setup() -> (Client, Runtime) { } fn query_prepared(c: &mut Criterion) { - let (client, mut runtime) = setup(); + let (client, runtime) = setup(); let statement = runtime.block_on(client.prepare("SELECT $1::INT8")).unwrap(); c.bench_function("runtime_block_on", move |b| { b.iter(|| { @@ -29,13 +29,13 @@ fn query_prepared(c: &mut Criterion) { }) }); - let (client, mut runtime) = setup(); + let (client, runtime) = setup(); let statement = runtime.block_on(client.prepare("SELECT $1::INT8")).unwrap(); c.bench_function("executor_block_on", move |b| { b.iter(|| executor::block_on(client.query(&statement, &[&1i64])).unwrap()) }); - let (client, mut runtime) = setup(); + let (client, runtime) = setup(); let client = Arc::new(client); let statement = runtime.block_on(client.prepare("SELECT $1::INT8")).unwrap(); c.bench_function("spawned", move |b| { diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 2d56a2ed5..145eb7dce 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -12,19 +12,15 @@ pub(crate) async fn connect_socket( host: &Host, port: u16, connect_timeout: Option, - keepalives: bool, - keepalives_idle: Duration, + _keepalives: bool, + _keepalives_idle: Duration, ) -> Result { match host { Host::Tcp(host) => { let socket = connect_with_timeout(TcpStream::connect((&**host, port)), connect_timeout).await?; socket.set_nodelay(true).map_err(Error::connect)?; - if keepalives { - socket - .set_keepalive(Some(keepalives_idle)) - .map_err(Error::connect)?; - } + // FIXME support keepalives? Ok(Socket::new_tcp(socket)) } diff --git a/tokio-postgres/src/maybe_tls_stream.rs b/tokio-postgres/src/maybe_tls_stream.rs index 652236ee8..73b0c4721 100644 --- a/tokio-postgres/src/maybe_tls_stream.rs +++ b/tokio-postgres/src/maybe_tls_stream.rs @@ -1,10 +1,8 @@ use crate::tls::{ChannelBinding, TlsStream}; -use bytes::{Buf, BufMut}; use std::io; -use std::mem::MaybeUninit; use std::pin::Pin; use std::task::{Context, Poll}; -use tokio::io::{AsyncRead, AsyncWrite}; +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; pub enum MaybeTlsStream { Raw(S), @@ -16,38 +14,16 @@ where S: AsyncRead + Unpin, T: AsyncRead + Unpin, { - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [MaybeUninit]) -> bool { - match self { - MaybeTlsStream::Raw(s) => s.prepare_uninitialized_buffer(buf), - MaybeTlsStream::Tls(s) => s.prepare_uninitialized_buffer(buf), - } - } - fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { + buf: &mut ReadBuf<'_>, + ) -> Poll> { match &mut *self { MaybeTlsStream::Raw(s) => Pin::new(s).poll_read(cx, buf), MaybeTlsStream::Tls(s) => Pin::new(s).poll_read(cx, buf), } } - - fn poll_read_buf( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut B, - ) -> Poll> - where - Self: Sized, - B: BufMut, - { - match &mut *self { - MaybeTlsStream::Raw(s) => Pin::new(s).poll_read_buf(cx, buf), - MaybeTlsStream::Tls(s) => Pin::new(s).poll_read_buf(cx, buf), - } - } } impl AsyncWrite for MaybeTlsStream @@ -79,21 +55,6 @@ where MaybeTlsStream::Tls(s) => Pin::new(s).poll_shutdown(cx), } } - - fn poll_write_buf( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut B, - ) -> Poll> - where - Self: Sized, - B: Buf, - { - match &mut *self { - MaybeTlsStream::Raw(s) => Pin::new(s).poll_write_buf(cx, buf), - MaybeTlsStream::Tls(s) => Pin::new(s).poll_write_buf(cx, buf), - } - } } impl TlsStream for MaybeTlsStream diff --git a/tokio-postgres/src/socket.rs b/tokio-postgres/src/socket.rs index cc7149674..966510d56 100644 --- a/tokio-postgres/src/socket.rs +++ b/tokio-postgres/src/socket.rs @@ -1,9 +1,7 @@ -use bytes::{Buf, BufMut}; use std::io; -use std::mem::MaybeUninit; use std::pin::Pin; use std::task::{Context, Poll}; -use tokio::io::{AsyncRead, AsyncWrite}; +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio::net::TcpStream; #[cfg(unix)] use tokio::net::UnixStream; @@ -33,41 +31,17 @@ impl Socket { } impl AsyncRead for Socket { - unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [MaybeUninit]) -> bool { - match &self.0 { - Inner::Tcp(s) => s.prepare_uninitialized_buffer(buf), - #[cfg(unix)] - Inner::Unix(s) => s.prepare_uninitialized_buffer(buf), - } - } - fn poll_read( mut self: Pin<&mut Self>, cx: &mut Context<'_>, - buf: &mut [u8], - ) -> Poll> { + buf: &mut ReadBuf<'_>, + ) -> Poll> { match &mut self.0 { Inner::Tcp(s) => Pin::new(s).poll_read(cx, buf), #[cfg(unix)] Inner::Unix(s) => Pin::new(s).poll_read(cx, buf), } } - - fn poll_read_buf( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut B, - ) -> Poll> - where - Self: Sized, - B: BufMut, - { - match &mut self.0 { - Inner::Tcp(s) => Pin::new(s).poll_read_buf(cx, buf), - #[cfg(unix)] - Inner::Unix(s) => Pin::new(s).poll_read_buf(cx, buf), - } - } } impl AsyncWrite for Socket { @@ -98,20 +72,4 @@ impl AsyncWrite for Socket { Inner::Unix(s) => Pin::new(s).poll_shutdown(cx), } } - - fn poll_write_buf( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: &mut B, - ) -> Poll> - where - Self: Sized, - B: Buf, - { - match &mut self.0 { - Inner::Tcp(s) => Pin::new(s).poll_write_buf(cx, buf), - #[cfg(unix)] - Inner::Unix(s) => Pin::new(s).poll_write_buf(cx, buf), - } - } } diff --git a/tokio-postgres/src/tls.rs b/tokio-postgres/src/tls.rs index 4e852d3f9..963daed18 100644 --- a/tokio-postgres/src/tls.rs +++ b/tokio-postgres/src/tls.rs @@ -5,7 +5,7 @@ use std::future::Future; use std::pin::Pin; use std::task::{Context, Poll}; use std::{fmt, io}; -use tokio::io::{AsyncRead, AsyncWrite}; +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; pub(crate) mod private { pub struct ForcePrivateApi; @@ -125,8 +125,8 @@ impl AsyncRead for NoTlsStream { fn poll_read( self: Pin<&mut Self>, _: &mut Context<'_>, - _: &mut [u8], - ) -> Poll> { + _: &mut ReadBuf<'_>, + ) -> Poll> { match *self {} } } diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index b01037edc..bf6d72d3e 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -308,7 +308,7 @@ async fn cancel_query_raw() { let socket = TcpStream::connect("127.0.0.1:5433").await.unwrap(); let cancel_token = client.cancel_token(); let cancel = cancel_token.cancel_query_raw(socket, NoTls); - let cancel = time::delay_for(Duration::from_millis(100)).then(|()| cancel); + let cancel = time::sleep(Duration::from_millis(100)).then(|()| cancel); let sleep = client.batch_execute("SELECT pg_sleep(100)"); diff --git a/tokio-postgres/tests/test/runtime.rs b/tokio-postgres/tests/test/runtime.rs index e07aa4a63..b088d6c98 100644 --- a/tokio-postgres/tests/test/runtime.rs +++ b/tokio-postgres/tests/test/runtime.rs @@ -72,7 +72,7 @@ async fn cancel_query() { let cancel_token = client.cancel_token(); let cancel = cancel_token.cancel_query(NoTls); - let cancel = time::delay_for(Duration::from_millis(100)).then(|()| cancel); + let cancel = time::sleep(Duration::from_millis(100)).then(|()| cancel); let sleep = client.batch_execute("SELECT pg_sleep(100)"); From b30182962f6aa354b233f8a229c1b87c9b196d20 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 17 Oct 2020 09:52:46 -0400 Subject: [PATCH 036/420] bump ci image --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f3dae7101..8038a2c0f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,7 +22,7 @@ version: 2 jobs: build: docker: - - image: rust:1.41.0 + - image: rust:1.45.0 environment: RUSTFLAGS: -D warnings - image: sfackler/rust-postgres-test:6 From 3f350680d57a9993ac5306bf52be7f17efe92d58 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 17 Oct 2020 14:53:34 -0400 Subject: [PATCH 037/420] Release postgres-protocol v0.5.3 --- postgres-protocol/CHANGELOG.md | 6 ++++++ postgres-protocol/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres-protocol/CHANGELOG.md b/postgres-protocol/CHANGELOG.md index 3cff60c51..b476fcabf 100644 --- a/postgres-protocol/CHANGELOG.md +++ b/postgres-protocol/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.5.3 - 2020-10-17 + +### Changed + +* Upgraded `base64` and `hmac`. + ## v0.5.2 - 2020-07-06 ### Changed diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index 0c89a5724..cb7657eea 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-protocol" -version = "0.5.2" +version = "0.5.3" authors = ["Steven Fackler "] edition = "2018" description = "Low level Postgres protocol APIs" From 7fd04e7a21cc5ae9832f24a4b28292b40fbcaa8f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 17 Oct 2020 15:00:47 -0400 Subject: [PATCH 038/420] Release postgres-types v0.1.3 --- postgres-types/CHANGELOG.md | 10 ++++++++++ postgres-types/Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index ddbdc6844..1c267923c 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## v0.1.3 - 2020-10-17 + +### Added + +* Implemented `Clone`, `PartialEq`, and `Eq` for `Json`. + +### Fixed + +* Checked for overflow in `NaiveDate` and `NaiveDateTime` conversions. + ## v0.1.2 - 2020-07-03 ### Added diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index b50653168..c5e706f6e 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-types" -version = "0.1.2" +version = "0.1.3" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From 12e2f03b53636b9348e07c5d83191a7c7805a0f4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 17 Oct 2020 15:05:09 -0400 Subject: [PATCH 039/420] Release tokio-postgres v0.6.0 --- postgres-native-tls/Cargo.toml | 2 +- postgres-openssl/Cargo.toml | 2 +- postgres/Cargo.toml | 2 +- tokio-postgres/CHANGELOG.md | 7 +++++++ tokio-postgres/Cargo.toml | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index 51145bf95..21b21c9eb 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -20,7 +20,7 @@ futures = "0.3" native-tls = "0.2" tokio = "0.3" tokio-native-tls = "0.2" -tokio-postgres = { version = "0.5.0", path = "../tokio-postgres", default-features = false } +tokio-postgres = { version = "0.6.0", path = "../tokio-postgres", default-features = false } [dev-dependencies] tokio = { version = "0.3", features = ["full"] } diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index e022a4f8a..d9bff72b8 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -20,7 +20,7 @@ futures = "0.3" openssl = "0.10" tokio = "0.3" tokio-openssl = "0.5" -tokio-postgres = { version = "0.5.0", path = "../tokio-postgres", default-features = false } +tokio-postgres = { version = "0.6.0", path = "../tokio-postgres", default-features = false } [dev-dependencies] tokio = { version = "0.3", features = ["full"] } diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index db9104453..24dc211eb 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -34,7 +34,7 @@ with-time-0_2 = ["tokio-postgres/with-time-0_2"] bytes = "0.5" fallible-iterator = "0.2" futures = "0.3" -tokio-postgres = { version = "0.5.5", path = "../tokio-postgres" } +tokio-postgres = { version = "0.6.0", path = "../tokio-postgres" } tokio = { version = "0.3", features = ["rt", "time"] } log = "0.4" diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index a02c461a5..95fd3ed6a 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## v0.6.0 - 2020-10-17 + +### Changed + +* Upgraded to tokio `0.3`. +* Added the detail and hint fields to `DbError`'s `Display` implementation. + ## v0.5.5 - 2020-07-03 ### Added diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index aea6aa5ca..63b216488 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.5.5" +version = "0.6.0" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From cc77ad18d5fc6059e565dc99fce5ec674c4138de Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 17 Oct 2020 15:16:56 -0400 Subject: [PATCH 040/420] Release postgres v0.18.0 --- postgres-native-tls/Cargo.toml | 2 +- postgres-openssl/Cargo.toml | 2 +- postgres/CHANGELOG.md | 14 ++++++++++++++ postgres/Cargo.toml | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index 21b21c9eb..b73a3bcca 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -24,4 +24,4 @@ tokio-postgres = { version = "0.6.0", path = "../tokio-postgres", default-featur [dev-dependencies] tokio = { version = "0.3", features = ["full"] } -postgres = { version = "0.17.0", path = "../postgres" } +postgres = { version = "0.18.0", path = "../postgres" } diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index d9bff72b8..bd5c64faa 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -24,4 +24,4 @@ tokio-postgres = { version = "0.6.0", path = "../tokio-postgres", default-featur [dev-dependencies] tokio = { version = "0.3", features = ["full"] } -postgres = { version = "0.17.0", path = "../postgres" } +postgres = { version = "0.18.0", path = "../postgres" } diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index 965bd2b09..c4e6b948d 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,5 +1,19 @@ # Change Log +## v0.18.0 - 2020-10-17 + +### Changed + +* Upgraded to `tokio-postgres` 0.6. + +### Added + +* Added `Config::notice_callback`, which can be used to provide a custom callback for notices. + +### Fixed + +* Fixed client shutdown to explicitly terminate the database session. + ## v0.17.5 - 2020-07-19 ### Fixed diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 24dc211eb..da4c6259f 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.17.5" +version = "0.18.0" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From 473562175fc685688b4364d121703ee82c7ab983 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 17 Oct 2020 15:18:28 -0400 Subject: [PATCH 041/420] Release postgres-native-tls v0.4.0 --- 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 fd9180b3d..a840592e3 100644 --- a/postgres-native-tls/CHANGELOG.md +++ b/postgres-native-tls/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.4.0 - 2020-10-17 + +### Changed + +* Upgraded to `tokio-postgres` 0.6. + ## v0.3.0 - 2019-12-23 ### Changed diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index b73a3bcca..81dcf29e3 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-native-tls" -version = "0.3.0" +version = "0.4.0" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From ec1c4a5c6533109e42adcf1fa9d5f60cbe1e2ba8 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 17 Oct 2020 15:20:32 -0400 Subject: [PATCH 042/420] Release postgres-openssl v0.4.0 --- 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 45a1bd065..f740828c5 100644 --- a/postgres-openssl/CHANGELOG.md +++ b/postgres-openssl/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.4.0 - 2020-10-17 + +### Changed + +* Upgraded to `tokio-postgres` 0.6. + ## v0.3.0 - 2019-12-23 ### Changed diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index bd5c64faa..c825e929d 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-openssl" -version = "0.3.0" +version = "0.4.0" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From 6561d8129a83fcb2037c4fd5546b56dc9676ae2a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 19 Oct 2020 13:23:29 +0000 Subject: [PATCH 043/420] Update env_logger requirement from 0.7 to 0.8 Updates the requirements on [env_logger](https://github.com/env-logger-rs/env_logger) to permit the latest version. - [Release notes](https://github.com/env-logger-rs/env_logger/releases) - [Changelog](https://github.com/env-logger-rs/env_logger/blob/master/CHANGELOG.md) - [Commits](https://github.com/env-logger-rs/env_logger/compare/v0.7.0...v0.8.1) Signed-off-by: dependabot-preview[bot] --- tokio-postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 63b216488..883f8e1ee 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -54,7 +54,7 @@ tokio-util = { version = "0.4", features = ["codec"] } [dev-dependencies] tokio = { version = "0.3", features = ["full"] } -env_logger = "0.7" +env_logger = "0.8" criterion = "0.3" bit-vec-06 = { version = "0.6", package = "bit-vec" } From a2ab2aab5b9db832d504e13b5e4eb51e02d0717e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 19 Oct 2020 13:24:08 +0000 Subject: [PATCH 044/420] Update hmac requirement from 0.9 to 0.10 Updates the requirements on [hmac](https://github.com/RustCrypto/MACs) to permit the latest version. - [Release notes](https://github.com/RustCrypto/MACs/releases) - [Commits](https://github.com/RustCrypto/MACs/compare/hmac-v0.9.0...hmac-v0.10.1) Signed-off-by: dependabot-preview[bot] --- 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 cb7657eea..5c7e11478 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -13,7 +13,7 @@ base64 = "0.13" byteorder = "1.0" bytes = "0.5" fallible-iterator = "0.2" -hmac = "0.9" +hmac = "0.10" md5 = "0.7" memchr = "2.0" rand = "0.7" From db90323b0806f6fb00f5012b2e80fe8658f19224 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 19 Oct 2020 19:58:41 -0400 Subject: [PATCH 045/420] Make postgres::Client Send again Closes #677 --- postgres/src/connection.rs | 4 ++-- postgres/src/test.rs | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/postgres/src/connection.rs b/postgres/src/connection.rs index bc8564f54..453eef3a6 100644 --- a/postgres/src/connection.rs +++ b/postgres/src/connection.rs @@ -16,14 +16,14 @@ pub struct Connection { runtime: Runtime, connection: Pin> + Send>>, notifications: VecDeque, - notice_callback: Arc, + notice_callback: Arc, } impl Connection { pub fn new( runtime: Runtime, connection: tokio_postgres::Connection, - notice_callback: Arc, + notice_callback: Arc, ) -> Connection where S: AsyncRead + AsyncWrite + Unpin + 'static + Send, diff --git a/postgres/src/test.rs b/postgres/src/test.rs index dcf202ef7..0fd404574 100644 --- a/postgres/src/test.rs +++ b/postgres/src/test.rs @@ -499,3 +499,12 @@ fn explicit_close() { let client = Client::connect("host=localhost port=5433 user=postgres", NoTls).unwrap(); client.close().unwrap(); } + +#[test] +fn check_send() { + fn is_send() {} + + is_send::(); + is_send::(); + is_send::>(); +} From 5e065c36cdcaa8741c712833a947670b46e952c3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 19 Oct 2020 20:02:01 -0400 Subject: [PATCH 046/420] Release v0.18.1 --- postgres/CHANGELOG.md | 6 ++++++ postgres/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index c4e6b948d..2c9443986 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.18.1 - 20201-10-19 + +### Fixed + +* Restored the `Send` implementation for `Client`. + ## v0.18.0 - 2020-10-17 ### Changed diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index da4c6259f..b84becd19 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.18.0" +version = "0.18.1" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From 0eab5fad70a0af4ce754560661cf263f5a847193 Mon Sep 17 00:00:00 2001 From: Bernardo Uriarte Blanco Date: Mon, 26 Oct 2020 20:59:28 +0100 Subject: [PATCH 047/420] make iterators from `&dyn ToSql` or `T: ToSql` work as parameters --- postgres-types/src/lib.rs | 18 +++++++++++++++ tokio-postgres/src/binary_copy.rs | 7 ++++-- tokio-postgres/src/bind.rs | 7 +++--- tokio-postgres/src/client.rs | 11 +++++---- tokio-postgres/src/query.rs | 38 +++++++++++++++++++++---------- 5 files changed, 60 insertions(+), 21 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index e9a5846e1..c8d65e77a 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -951,3 +951,21 @@ fn downcast(len: usize) -> Result> { Ok(len as i32) } } + +/// A helper trait to be able create a parameters iterator from `&dyn ToSql` or `T: ToSql` +pub trait BorrowToSql { + /// Get a reference to a `ToSql` trait object + fn borrow_to_sql(&self) -> &dyn ToSql; +} + +impl BorrowToSql for &dyn ToSql { + fn borrow_to_sql(&self) -> &dyn ToSql { + *self + } +} + +impl BorrowToSql for T { + fn borrow_to_sql(&self) -> &dyn ToSql { + self + } +} diff --git a/tokio-postgres/src/binary_copy.rs b/tokio-postgres/src/binary_copy.rs index 231f202d8..20064c728 100644 --- a/tokio-postgres/src/binary_copy.rs +++ b/tokio-postgres/src/binary_copy.rs @@ -6,6 +6,7 @@ use byteorder::{BigEndian, ByteOrder}; use bytes::{Buf, BufMut, Bytes, BytesMut}; use futures::{ready, SinkExt, Stream}; use pin_project_lite::pin_project; +use postgres_types::BorrowToSql; use std::convert::TryFrom; use std::io; use std::io::Cursor; @@ -58,9 +59,10 @@ impl BinaryCopyInWriter { /// # Panics /// /// Panics if the number of values provided does not match the number expected. - pub async fn write_raw<'a, I>(self: Pin<&mut Self>, values: I) -> Result<(), Error> + pub async fn write_raw(self: Pin<&mut Self>, values: I) -> Result<(), Error> where - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { let mut this = self.project(); @@ -79,6 +81,7 @@ impl BinaryCopyInWriter { let idx = this.buf.len(); this.buf.put_i32(0); let len = match value + .borrow_to_sql() .to_sql_checked(type_, this.buf) .map_err(|e| Error::to_sql(e, i))? { diff --git a/tokio-postgres/src/bind.rs b/tokio-postgres/src/bind.rs index 69823a9ab..9c5c49218 100644 --- a/tokio-postgres/src/bind.rs +++ b/tokio-postgres/src/bind.rs @@ -1,7 +1,7 @@ use crate::client::InnerClient; use crate::codec::FrontendMessage; use crate::connection::RequestMessages; -use crate::types::ToSql; +use crate::types::BorrowToSql; use crate::{query, Error, Portal, Statement}; use postgres_protocol::message::backend::Message; use postgres_protocol::message::frontend; @@ -10,13 +10,14 @@ use std::sync::Arc; static NEXT_ID: AtomicUsize = AtomicUsize::new(0); -pub async fn bind<'a, I>( +pub async fn bind( client: &Arc, statement: Statement, params: I, ) -> Result where - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { let name = format!("p{}", NEXT_ID.fetch_add(1, Ordering::SeqCst)); diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index e19caae83..ecf3ea601 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -20,6 +20,7 @@ use futures::channel::mpsc; use futures::{future, pin_mut, ready, StreamExt, TryStreamExt}; use parking_lot::Mutex; use postgres_protocol::message::backend::Message; +use postgres_types::BorrowToSql; use std::collections::HashMap; use std::fmt; use std::sync::Arc; @@ -342,10 +343,11 @@ impl Client { /// # Ok(()) /// # } /// ``` - pub async fn query_raw<'a, T, I>(&self, statement: &T, params: I) -> Result + pub async fn query_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement, - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { let statement = statement.__convert().into_statement(self).await?; @@ -391,10 +393,11 @@ impl Client { /// Panics if the number of parameters provided does not match the number expected. /// /// [`execute`]: #method.execute - pub async fn execute_raw<'a, T, I>(&self, statement: &T, params: I) -> Result + pub async fn execute_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement, - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { let statement = statement.__convert().into_statement(self).await?; diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index 7792f0a8a..2245b982a 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -1,7 +1,7 @@ use crate::client::{InnerClient, Responses}; use crate::codec::FrontendMessage; use crate::connection::RequestMessages; -use crate::types::{IsNull, ToSql}; +use crate::types::{BorrowToSql, IsNull}; use crate::{Error, Portal, Row, Statement}; use bytes::{Bytes, BytesMut}; use futures::{ready, Stream}; @@ -9,17 +9,28 @@ use log::{debug, log_enabled, Level}; use pin_project_lite::pin_project; use postgres_protocol::message::backend::Message; use postgres_protocol::message::frontend; +use std::fmt; use std::marker::PhantomPinned; use std::pin::Pin; use std::task::{Context, Poll}; -pub async fn query<'a, I>( +struct BorrowToSqlParamsDebug<'a, T: BorrowToSql>(&'a [T]); +impl<'a, T: BorrowToSql> std::fmt::Debug for BorrowToSqlParamsDebug<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list() + .entries(self.0.iter().map(|x| x.borrow_to_sql())) + .finish() + } +} + +pub async fn query( client: &InnerClient, statement: Statement, params: I, ) -> Result where - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { let buf = if log_enabled!(Level::Debug) { @@ -27,7 +38,7 @@ where debug!( "executing statement {} with parameters: {:?}", statement.name(), - params, + BorrowToSqlParamsDebug(params.as_slice()), ); encode(client, &statement, params)? } else { @@ -61,13 +72,14 @@ pub async fn query_portal( }) } -pub async fn execute<'a, I>( +pub async fn execute( client: &InnerClient, statement: Statement, params: I, ) -> Result where - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { let buf = if log_enabled!(Level::Debug) { @@ -75,7 +87,7 @@ where debug!( "executing statement {} with parameters: {:?}", statement.name(), - params, + BorrowToSqlParamsDebug(params.as_slice()), ); encode(client, &statement, params)? } else { @@ -114,9 +126,10 @@ async fn start(client: &InnerClient, buf: Bytes) -> Result { Ok(responses) } -pub fn encode<'a, I>(client: &InnerClient, statement: &Statement, params: I) -> Result +pub fn encode(client: &InnerClient, statement: &Statement, params: I) -> Result where - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { client.with_buf(|buf| { @@ -127,14 +140,15 @@ where }) } -pub fn encode_bind<'a, I>( +pub fn encode_bind( statement: &Statement, params: I, portal: &str, buf: &mut BytesMut, ) -> Result<(), Error> where - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { let params = params.into_iter(); @@ -152,7 +166,7 @@ where statement.name(), Some(1), params.zip(statement.params()).enumerate(), - |(idx, (param, ty)), buf| match param.to_sql_checked(ty, buf) { + |(idx, (param, ty)), buf| match param.borrow_to_sql().to_sql_checked(ty, buf) { Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No), Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes), Err(e) => { From 0e494a08a982bcd743c71e05f366fb51da86e075 Mon Sep 17 00:00:00 2001 From: Bernardo Uriarte Blanco Date: Tue, 27 Oct 2020 18:08:23 +0100 Subject: [PATCH 048/420] change rest of `*_raw` methods to use `BorrowToSql` --- postgres/src/binary_copy.rs | 7 +++--- postgres/src/client.rs | 9 ++++---- postgres/src/generic_client.rs | 17 +++++++++------ postgres/src/transaction.rs | 7 +++--- tokio-postgres/src/generic_client.rs | 32 +++++++++++++++++----------- tokio-postgres/src/transaction.rs | 17 +++++++++------ 6 files changed, 52 insertions(+), 37 deletions(-) diff --git a/postgres/src/binary_copy.rs b/postgres/src/binary_copy.rs index 259347195..98ae666b7 100644 --- a/postgres/src/binary_copy.rs +++ b/postgres/src/binary_copy.rs @@ -1,7 +1,7 @@ //! Utilities for working with the PostgreSQL binary copy format. use crate::connection::ConnectionRef; -use crate::types::{ToSql, Type}; +use crate::types::{BorrowToSql, ToSql, Type}; use crate::{CopyInWriter, CopyOutReader, Error}; use fallible_iterator::FallibleIterator; use futures::StreamExt; @@ -46,9 +46,10 @@ impl<'a> BinaryCopyInWriter<'a> { /// # Panics /// /// Panics if the number of values provided does not match the number expected. - pub fn write_raw<'b, I>(&mut self, values: I) -> Result<(), Error> + pub fn write_raw(&mut self, values: I) -> Result<(), Error> where - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { self.connection diff --git a/postgres/src/client.rs b/postgres/src/client.rs index dcb9c72d4..8ea038da4 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -5,7 +5,7 @@ use crate::{ }; use std::task::Poll; use tokio_postgres::tls::{MakeTlsConnect, TlsConnect}; -use tokio_postgres::types::{ToSql, Type}; +use tokio_postgres::types::{BorrowToSql, ToSql, Type}; use tokio_postgres::{Error, Row, SimpleQueryMessage, Socket}; /// A synchronous PostgreSQL client. @@ -227,7 +227,7 @@ impl Client { /// let mut client = Client::connect("host=localhost user=postgres", NoTls)?; /// /// let baz = true; - /// let mut it = client.query_raw("SELECT foo FROM bar WHERE baz = $1", iter::once(&baz as _))?; + /// let mut it = client.query_raw("SELECT foo FROM bar WHERE baz = $1", iter::once(baz))?; /// /// while let Some(row) = it.next()? { /// let foo: i32 = row.get("foo"); @@ -263,10 +263,11 @@ impl Client { /// # Ok(()) /// # } /// ``` - pub fn query_raw<'a, T, I>(&mut self, query: &T, params: I) -> Result, Error> + pub fn query_raw(&mut self, query: &T, params: I) -> Result, Error> where T: ?Sized + ToStatement, - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { let stream = self diff --git a/postgres/src/generic_client.rs b/postgres/src/generic_client.rs index 42a466df6..12f07465d 100644 --- a/postgres/src/generic_client.rs +++ b/postgres/src/generic_client.rs @@ -1,4 +1,4 @@ -use crate::types::{ToSql, Type}; +use crate::types::{BorrowToSql, ToSql, Type}; use crate::{ Client, CopyInWriter, CopyOutReader, Error, Row, RowIter, SimpleQueryMessage, Statement, ToStatement, Transaction, @@ -37,10 +37,11 @@ pub trait GenericClient: private::Sealed { T: ?Sized + ToStatement; /// Like `Client::query_raw`. - fn query_raw<'a, T, I>(&mut self, query: &T, params: I) -> Result, Error> + fn query_raw(&mut self, query: &T, params: I) -> Result, Error> where T: ?Sized + ToStatement, - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator; /// Like `Client::prepare`. @@ -104,10 +105,11 @@ impl GenericClient for Client { self.query_opt(query, params) } - fn query_raw<'a, T, I>(&mut self, query: &T, params: I) -> Result, Error> + fn query_raw(&mut self, query: &T, params: I) -> Result, Error> where T: ?Sized + ToStatement, - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { self.query_raw(query, params) @@ -183,10 +185,11 @@ impl GenericClient for Transaction<'_> { self.query_opt(query, params) } - fn query_raw<'a, T, I>(&mut self, query: &T, params: I) -> Result, Error> + fn query_raw(&mut self, query: &T, params: I) -> Result, Error> where T: ?Sized + ToStatement, - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { self.query_raw(query, params) diff --git a/postgres/src/transaction.rs b/postgres/src/transaction.rs index 3213b7c1f..17c49c406 100644 --- a/postgres/src/transaction.rs +++ b/postgres/src/transaction.rs @@ -1,6 +1,6 @@ use crate::connection::ConnectionRef; use crate::{CancelToken, CopyInWriter, CopyOutReader, Portal, RowIter, Statement, ToStatement}; -use tokio_postgres::types::{ToSql, Type}; +use tokio_postgres::types::{BorrowToSql, ToSql, Type}; use tokio_postgres::{Error, Row, SimpleQueryMessage}; /// A representation of a PostgreSQL database transaction. @@ -102,10 +102,11 @@ impl<'a> Transaction<'a> { } /// Like `Client::query_raw`. - pub fn query_raw<'b, T, I>(&mut self, query: &T, params: I) -> Result, Error> + pub fn query_raw(&mut self, query: &T, params: I) -> Result, Error> where T: ?Sized + ToStatement, - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { let stream = self diff --git a/tokio-postgres/src/generic_client.rs b/tokio-postgres/src/generic_client.rs index ad318e864..df2c6b842 100644 --- a/tokio-postgres/src/generic_client.rs +++ b/tokio-postgres/src/generic_client.rs @@ -1,5 +1,5 @@ use crate::query::RowStream; -use crate::types::{ToSql, Type}; +use crate::types::{BorrowToSql, ToSql, Type}; use crate::{Client, Error, Row, Statement, ToStatement, Transaction}; use async_trait::async_trait; @@ -18,10 +18,11 @@ pub trait GenericClient: private::Sealed { T: ?Sized + ToStatement + Sync + Send; /// Like `Client::execute_raw`. - async fn execute_raw<'b, I, T>(&self, statement: &T, params: I) -> Result + async fn execute_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement + Sync + Send, - I: IntoIterator + Sync + Send, + P: BorrowToSql, + I: IntoIterator + Sync + Send, I::IntoIter: ExactSizeIterator; /// Like `Client::query`. @@ -48,10 +49,11 @@ pub trait GenericClient: private::Sealed { T: ?Sized + ToStatement + Sync + Send; /// Like `Client::query_raw`. - async fn query_raw<'b, T, I>(&self, statement: &T, params: I) -> Result + async fn query_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement + Sync + Send, - I: IntoIterator + Sync + Send, + P: BorrowToSql, + I: IntoIterator + Sync + Send, I::IntoIter: ExactSizeIterator; /// Like `Client::prepare`. @@ -79,10 +81,11 @@ impl GenericClient for Client { self.execute(query, params).await } - async fn execute_raw<'b, I, T>(&self, statement: &T, params: I) -> Result + async fn execute_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement + Sync + Send, - I: IntoIterator + Sync + Send, + P: BorrowToSql, + I: IntoIterator + Sync + Send, I::IntoIter: ExactSizeIterator, { self.execute_raw(statement, params).await @@ -117,10 +120,11 @@ impl GenericClient for Client { self.query_opt(statement, params).await } - async fn query_raw<'b, T, I>(&self, statement: &T, params: I) -> Result + async fn query_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement + Sync + Send, - I: IntoIterator + Sync + Send, + P: BorrowToSql, + I: IntoIterator + Sync + Send, I::IntoIter: ExactSizeIterator, { self.query_raw(statement, params).await @@ -155,10 +159,11 @@ impl GenericClient for Transaction<'_> { self.execute(query, params).await } - async fn execute_raw<'b, I, T>(&self, statement: &T, params: I) -> Result + async fn execute_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement + Sync + Send, - I: IntoIterator + Sync + Send, + P: BorrowToSql, + I: IntoIterator + Sync + Send, I::IntoIter: ExactSizeIterator, { self.execute_raw(statement, params).await @@ -193,10 +198,11 @@ impl GenericClient for Transaction<'_> { self.query_opt(statement, params).await } - async fn query_raw<'b, T, I>(&self, statement: &T, params: I) -> Result + async fn query_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement + Sync + Send, - I: IntoIterator + Sync + Send, + P: BorrowToSql, + I: IntoIterator + Sync + Send, I::IntoIter: ExactSizeIterator, { self.query_raw(statement, params).await diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index 38fdf7cea..45e9cc3aa 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -5,7 +5,7 @@ use crate::query::RowStream; #[cfg(feature = "runtime")] use crate::tls::MakeTlsConnect; use crate::tls::TlsConnect; -use crate::types::{ToSql, Type}; +use crate::types::{BorrowToSql, ToSql, Type}; #[cfg(feature = "runtime")] use crate::Socket; use crate::{ @@ -139,10 +139,11 @@ impl<'a> Transaction<'a> { } /// Like `Client::query_raw`. - pub async fn query_raw<'b, T, I>(&self, statement: &T, params: I) -> Result + pub async fn query_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement, - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { self.client.query_raw(statement, params).await @@ -161,10 +162,11 @@ impl<'a> Transaction<'a> { } /// Like `Client::execute_iter`. - pub async fn execute_raw<'b, I, T>(&self, statement: &T, params: I) -> Result + pub async fn execute_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement, - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { self.client.execute_raw(statement, params).await @@ -192,10 +194,11 @@ impl<'a> Transaction<'a> { /// A maximally flexible version of [`bind`]. /// /// [`bind`]: #method.bind - pub async fn bind_raw<'b, T, I>(&self, statement: &T, params: I) -> Result + pub async fn bind_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement, - I: IntoIterator, + P: BorrowToSql, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { let statement = statement.__convert().into_statement(&self.client).await?; From 42dcfb584afea518e5b487e352c8ba87b75c571f Mon Sep 17 00:00:00 2001 From: Bernardo Uriarte Blanco Date: Tue, 27 Oct 2020 20:23:57 +0100 Subject: [PATCH 049/420] seal BorrowToSql --- postgres-types/src/lib.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index c8d65e77a..6542fc592 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -108,6 +108,7 @@ #![doc(html_root_url = "https://docs.rs/postgres-types/0.1")] #![warn(clippy::all, rust_2018_idioms, missing_docs)] +use crate::sealed::Sealed; use fallible_iterator::FallibleIterator; use postgres_protocol::types::{self, ArrayDimension}; use std::any::type_name; @@ -952,18 +953,29 @@ fn downcast(len: usize) -> Result> { } } -/// A helper trait to be able create a parameters iterator from `&dyn ToSql` or `T: ToSql` -pub trait BorrowToSql { +mod sealed { + pub trait Sealed {} +} + +/// A helper trait used internally by Rust-Postgres +/// to be able create a parameters iterator from `&dyn ToSql` or `T: ToSql`. +/// +/// /// This cannot be implemented outside of this crate. +pub trait BorrowToSql: sealed::Sealed { /// Get a reference to a `ToSql` trait object fn borrow_to_sql(&self) -> &dyn ToSql; } +impl Sealed for &dyn ToSql {} + impl BorrowToSql for &dyn ToSql { fn borrow_to_sql(&self) -> &dyn ToSql { *self } } +impl Sealed for T {} + impl BorrowToSql for T { fn borrow_to_sql(&self) -> &dyn ToSql { self From 996f0633802267ce45cf7170d2c8a935f22b534e Mon Sep 17 00:00:00 2001 From: Bernardo Uriarte Blanco Date: Tue, 27 Oct 2020 20:31:15 +0100 Subject: [PATCH 050/420] map to convert to `&dyn ToSql` is not longer necessary --- postgres/src/client.rs | 2 +- tokio-postgres/src/client.rs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/postgres/src/client.rs b/postgres/src/client.rs index 8ea038da4..f5637cdbd 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -253,7 +253,7 @@ impl Client { /// ]; /// let mut it = client.query_raw( /// "SELECT foo FROM bar WHERE biz = $1 AND baz = $2", - /// params.iter().map(|p| p as &dyn ToSql), + /// params, /// )?; /// /// while let Some(row) = it.next()? { diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index ecf3ea601..359a7cd16 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -318,9 +318,6 @@ impl Client { /// /// # Examples /// - /// If you have a type like `Vec` where `T: ToSql` Rust will not know how to use it as params. To get around - /// this the type must explicitly be converted to `&dyn ToSql`. - /// /// ```no_run /// # async fn async_main(client: &tokio_postgres::Client) -> Result<(), tokio_postgres::Error> { /// use tokio_postgres::types::ToSql; @@ -332,7 +329,7 @@ impl Client { /// ]; /// let mut it = client.query_raw( /// "SELECT foo FROM bar WHERE biz = $1 AND baz = $2", - /// params.iter().map(|p| p as &dyn ToSql), + /// params, /// ).await?; /// /// pin_mut!(it); From 46b4b8008cfb8283b7cf73e698bbf7737b5aca1e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 27 Oct 2020 19:16:20 -0400 Subject: [PATCH 051/420] Update postgres-types/src/lib.rs --- 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 6542fc592..ecda2fbd2 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -960,7 +960,7 @@ mod sealed { /// A helper trait used internally by Rust-Postgres /// to be able create a parameters iterator from `&dyn ToSql` or `T: ToSql`. /// -/// /// This cannot be implemented outside of this crate. +/// This cannot be implemented outside of this crate. pub trait BorrowToSql: sealed::Sealed { /// Get a reference to a `ToSql` trait object fn borrow_to_sql(&self) -> &dyn ToSql; From bbf31696bb4ed1d7727d3de6bf747975a0dcae1d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 27 Oct 2020 19:45:55 -0400 Subject: [PATCH 052/420] Cleanups --- postgres-types/src/lib.rs | 17 ++++++++++------- tokio-postgres/src/query.rs | 8 ++++++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index ecda2fbd2..7e81998b3 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -108,7 +108,6 @@ #![doc(html_root_url = "https://docs.rs/postgres-types/0.1")] #![warn(clippy::all, rust_2018_idioms, missing_docs)] -use crate::sealed::Sealed; use fallible_iterator::FallibleIterator; use postgres_protocol::types::{self, ArrayDimension}; use std::any::type_name; @@ -957,26 +956,30 @@ mod sealed { pub trait Sealed {} } -/// A helper trait used internally by Rust-Postgres -/// to be able create a parameters iterator from `&dyn ToSql` or `T: ToSql`. +/// A trait used by clients to abstract over `&dyn ToSql` and `T: ToSql`. /// /// This cannot be implemented outside of this crate. pub trait BorrowToSql: sealed::Sealed { - /// Get a reference to a `ToSql` trait object + /// Returns a reference to `self` as a `ToSql` trait object. fn borrow_to_sql(&self) -> &dyn ToSql; } -impl Sealed for &dyn ToSql {} +impl sealed::Sealed for &dyn ToSql {} impl BorrowToSql for &dyn ToSql { + #[inline] fn borrow_to_sql(&self) -> &dyn ToSql { *self } } -impl Sealed for T {} +impl sealed::Sealed for T where T: ToSql {} -impl BorrowToSql for T { +impl BorrowToSql for T +where + T: ToSql, +{ + #[inline] fn borrow_to_sql(&self) -> &dyn ToSql { self } diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index 2245b982a..f139ed915 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -14,8 +14,12 @@ use std::marker::PhantomPinned; use std::pin::Pin; use std::task::{Context, Poll}; -struct BorrowToSqlParamsDebug<'a, T: BorrowToSql>(&'a [T]); -impl<'a, T: BorrowToSql> std::fmt::Debug for BorrowToSqlParamsDebug<'a, T> { +struct BorrowToSqlParamsDebug<'a, T>(&'a [T]); + +impl<'a, T> fmt::Debug for BorrowToSqlParamsDebug<'a, T> +where + T: BorrowToSql, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list() .entries(self.0.iter().map(|x| x.borrow_to_sql())) From 5ad3c9a139303ba0c63b5c06337790a41d6474a2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 5 Nov 2020 21:14:56 -0500 Subject: [PATCH 053/420] Add back keepalives config handling Also fix connection timeouts to be per-address --- tokio-postgres/Cargo.toml | 1 + tokio-postgres/src/connect_socket.rs | 55 ++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 883f8e1ee..14f8c7e9d 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -49,6 +49,7 @@ pin-project-lite = "0.1" phf = "0.8" postgres-protocol = { version = "0.5.0", path = "../postgres-protocol" } postgres-types = { version = "0.1.2", path = "../postgres-types" } +socket2 = "0.3" tokio = { version = "0.3", features = ["io-util"] } tokio-util = { version = "0.4", features = ["codec"] } diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 145eb7dce..564677b05 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -1,28 +1,67 @@ use crate::config::Host; use crate::{Error, Socket}; +use socket2::{Domain, Protocol, Type}; use std::future::Future; use std::io; +use std::net::SocketAddr; +#[cfg(unix)] +use std::os::unix::io::{FromRawFd, IntoRawFd}; +#[cfg(windows)] +use std::os::windows::io::{FromRawSocket, IntoRawSocket}; use std::time::Duration; -use tokio::net::TcpStream; #[cfg(unix)] use tokio::net::UnixStream; +use tokio::net::{self, TcpSocket}; use tokio::time; pub(crate) async fn connect_socket( host: &Host, port: u16, connect_timeout: Option, - _keepalives: bool, - _keepalives_idle: Duration, + keepalives: bool, + keepalives_idle: Duration, ) -> Result { match host { Host::Tcp(host) => { - let socket = - connect_with_timeout(TcpStream::connect((&**host, port)), connect_timeout).await?; - socket.set_nodelay(true).map_err(Error::connect)?; - // FIXME support keepalives? + let addrs = net::lookup_host((&**host, port)) + .await + .map_err(Error::connect)?; + + let mut last_err = None; + + for addr in addrs { + let domain = match addr { + SocketAddr::V4(_) => Domain::ipv4(), + SocketAddr::V6(_) => Domain::ipv6(), + }; + + let socket = socket2::Socket::new(domain, Type::stream(), Some(Protocol::tcp())) + .map_err(Error::connect)?; + socket.set_nonblocking(true).map_err(Error::connect)?; + socket.set_nodelay(true).map_err(Error::connect)?; + if keepalives { + socket + .set_keepalive(Some(keepalives_idle)) + .map_err(Error::connect)?; + } + + #[cfg(unix)] + let socket = unsafe { TcpSocket::from_raw_fd(socket.into_raw_fd()) }; + #[cfg(windows)] + let socket = unsafe { TcpSocket::from_raw_socket(socket.into_raw_socket()) }; + + match connect_with_timeout(socket.connect(addr), connect_timeout).await { + Ok(socket) => return Ok(Socket::new_tcp(socket)), + Err(e) => last_err = Some(e), + } + } - Ok(Socket::new_tcp(socket)) + Err(last_err.unwrap_or_else(|| { + Error::connect(io::Error::new( + io::ErrorKind::InvalidInput, + "could not resolve any addresses", + )) + })) } #[cfg(unix)] Host::Unix(path) => { From c4b1f5ab5c1d0430c6489f2da39aa7a058373bdd Mon Sep 17 00:00:00 2001 From: Nicolas Guiard Date: Wed, 11 Nov 2020 11:14:28 +0100 Subject: [PATCH 054/420] Fix unix socket location in docs (/var/run/postgresql instead of /var/lib/postgresql) --- postgres/src/config.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index 249e6b44e..c8dffa330 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -59,7 +59,7 @@ use tokio_postgres::{Error, Socket}; /// ``` /// /// ```not_rust -/// host=/var/lib/postgresql,localhost port=1234 user=postgres password='password with spaces' +/// host=/var/run/postgresql,localhost port=1234 user=postgres password='password with spaces' /// ``` /// /// ```not_rust @@ -80,7 +80,7 @@ use tokio_postgres::{Error, Socket}; /// ``` /// /// ```not_rust -/// postgresql://user:password@%2Fvar%2Flib%2Fpostgresql/mydb?connect_timeout=10 +/// postgresql://user:password@%2Fvar%2Frun%2Fpostgresql/mydb?connect_timeout=10 /// ``` /// /// ```not_rust @@ -88,7 +88,7 @@ use tokio_postgres::{Error, Socket}; /// ``` /// /// ```not_rust -/// postgresql:///mydb?user=user&host=/var/lib/postgresql +/// postgresql:///mydb?user=user&host=/var/run/postgresql /// ``` #[derive(Clone)] pub struct Config { From 235dfeb95ad81a62fa036a3e9cc64bfd0e1293d2 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 17 Nov 2020 13:29:23 +0000 Subject: [PATCH 055/420] Update pin-project-lite requirement from 0.1 to 0.2 Updates the requirements on [pin-project-lite](https://github.com/taiki-e/pin-project-lite) to permit the latest version. - [Release notes](https://github.com/taiki-e/pin-project-lite/releases) - [Changelog](https://github.com/taiki-e/pin-project-lite/blob/master/CHANGELOG.md) - [Commits](https://github.com/taiki-e/pin-project-lite/compare/v0.1.0...v0.2.0) Signed-off-by: dependabot-preview[bot] --- tokio-postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 14f8c7e9d..f659663e1 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -45,7 +45,7 @@ futures = "0.3" log = "0.4" parking_lot = "0.11" percent-encoding = "2.0" -pin-project-lite = "0.1" +pin-project-lite = "0.2" phf = "0.8" postgres-protocol = { version = "0.5.0", path = "../postgres-protocol" } postgres-types = { version = "0.1.2", path = "../postgres-types" } From aadf9420ef64e0f3775a3385446f65bcd904516d Mon Sep 17 00:00:00 2001 From: Jeff Davis Date: Sat, 28 Nov 2020 19:38:05 -0800 Subject: [PATCH 056/420] Add escape_identifier() and escape_literal(). --- postgres-protocol/src/escape/mod.rs | 93 ++++++++++++++++++++++++++++ postgres-protocol/src/escape/test.rs | 17 +++++ postgres-protocol/src/lib.rs | 1 + 3 files changed, 111 insertions(+) create mode 100644 postgres-protocol/src/escape/mod.rs create mode 100644 postgres-protocol/src/escape/test.rs diff --git a/postgres-protocol/src/escape/mod.rs b/postgres-protocol/src/escape/mod.rs new file mode 100644 index 000000000..4b3b56cd5 --- /dev/null +++ b/postgres-protocol/src/escape/mod.rs @@ -0,0 +1,93 @@ +//! Provides functions for escaping literals and identifiers for use +//! in SQL queries. +//! +//! Prefer parameterized queries where possible; see +//! [`Client::query`](crate::Client::query). Do not escape parameters. + +#[cfg(test)] +mod test; + +/// Escape a literal and surround result with single quotes. Not +/// recommended in most cases. +/// +/// If input contains backslashes, result will be of the form ` +/// E'...'` so it is safe to use regardless of the setting of +/// standard_conforming_strings. +pub fn escape_literal(input: &str) -> String { + escape_internal(input, false) +} + +/// Escape an identifier and surround result with double quotes. +pub fn escape_identifier(input: &str) -> String { + escape_internal(input, true) +} + +// Translation of PostgreSQL libpq's PQescapeInternal(). Does not +// require a connection because input string is known to be valid +// UTF-8. +// +// Escape arbitrary strings. If as_ident is true, we escape the +// result as an identifier; if false, as a literal. The result is +// returned in a newly allocated buffer. If we fail due to an +// encoding violation or out of memory condition, we return NULL, +// storing an error message into conn. +fn escape_internal(input: &str, as_ident: bool) -> String { + let mut num_backslashes = 0; + let mut num_quotes = 0; + let quote_char = if as_ident { '"' } else { '\'' }; + + // Scan the string for characters that must be escaped. + for ch in input.chars() { + if ch == quote_char { + num_quotes += 1; + } else if ch == '\\' { + num_backslashes += 1; + } + } + + // Allocate output String. + let mut result_size = input.len() + num_quotes + 3; // two quotes, plus a NUL + if !as_ident && num_backslashes > 0 { + result_size += num_backslashes + 2; + } + + let mut output = String::with_capacity(result_size); + + // If we are escaping a literal that contains backslashes, we use + // the escape string syntax so that the result is correct under + // either value of standard_conforming_strings. We also emit a + // leading space in this case, to guard against the possibility + // that the result might be interpolated immediately following an + // identifier. + if !as_ident && num_backslashes > 0 { + output.push(' '); + output.push('E'); + } + + // Opening quote. + output.push(quote_char); + + // Use fast path if possible. + // + // We've already verified that the input string is well-formed in + // the current encoding. If it contains no quotes and, in the + // case of literal-escaping, no backslashes, then we can just copy + // it directly to the output buffer, adding the necessary quotes. + // + // If not, we must rescan the input and process each character + // individually. + if num_quotes == 0 && (num_backslashes == 0 || as_ident) { + output.push_str(input); + } else { + for ch in input.chars() { + if ch == quote_char || (!as_ident && ch == '\\') { + output.push(ch); + } + output.push(ch); + } + } + + output.push(quote_char); + + output +} diff --git a/postgres-protocol/src/escape/test.rs b/postgres-protocol/src/escape/test.rs new file mode 100644 index 000000000..4816a103b --- /dev/null +++ b/postgres-protocol/src/escape/test.rs @@ -0,0 +1,17 @@ +use crate::escape::{escape_identifier, escape_literal}; + +#[test] +fn test_escape_idenifier() { + assert_eq!(escape_identifier("foo"), String::from("\"foo\"")); + assert_eq!(escape_identifier("f\\oo"), String::from("\"f\\oo\"")); + assert_eq!(escape_identifier("f'oo"), String::from("\"f'oo\"")); + assert_eq!(escape_identifier("f\"oo"), String::from("\"f\"\"oo\"")); +} + +#[test] +fn test_escape_literal() { + assert_eq!(escape_literal("foo"), String::from("'foo'")); + assert_eq!(escape_literal("f\\oo"), String::from(" E'f\\\\oo'")); + assert_eq!(escape_literal("f'oo"), String::from("'f''oo'")); + assert_eq!(escape_literal("f\"oo"), String::from("'f\"oo'")); +} diff --git a/postgres-protocol/src/lib.rs b/postgres-protocol/src/lib.rs index 9ebbcba59..b4374afa1 100644 --- a/postgres-protocol/src/lib.rs +++ b/postgres-protocol/src/lib.rs @@ -17,6 +17,7 @@ use bytes::{BufMut, BytesMut}; use std::io; pub mod authentication; +pub mod escape; pub mod message; pub mod types; From 55dddc5c74e7e2f633fcad97201937c24dfdfff0 Mon Sep 17 00:00:00 2001 From: Jeff Davis Date: Mon, 30 Nov 2020 09:27:21 -0800 Subject: [PATCH 057/420] Add instructions for running tests. --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index cbe7182c6..3af068174 100644 --- a/README.md +++ b/README.md @@ -32,3 +32,16 @@ TLS support for postgres and tokio-postgres via native-tls. [Documentation](https://docs.rs/postgres-openssl) TLS support for postgres and tokio-postgres via openssl. + +# Running test suite + +The test suite requires postgres to be running in the correct configuration. The easiest way to do this is with docker: + +1. Install `docker` and `docker-compose`. + 1. On ubuntu: `sudo apt install docker.io docker-compose`. +1. Make sure your user has permissions for docker. + 1. On ubuntu: ``sudo usermod -aG docker $USER`` +1. Change to top-level directory of `rust-postgres` repo. +1. Run `docker-compose up -d`. +1. Run `cargo test`. +1. Run `docker-compose stop`. From fa8fb83ec8815ff85994a5ed46dfe5574efffd37 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Tue, 1 Dec 2020 18:20:37 +0300 Subject: [PATCH 058/420] Fix tokio features for runtime feature in the docs --- tokio-postgres/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index c69fff793..8a29dfd00 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -103,7 +103,7 @@ //! //! | Feature | Description | Extra dependencies | Default | //! | ------- | ----------- | ------------------ | ------- | -//! | `runtime` | Enable convenience API for the connection process based on the `tokio` crate. | [tokio](https://crates.io/crates/tokio) 0.2 with the features `dns`, `net` and `time` | yes | +//! | `runtime` | Enable convenience API for the connection process based on the `tokio` crate. | [tokio](https://crates.io/crates/tokio) 0.3 with the `io-util` feature | yes | //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | //! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | @@ -112,7 +112,7 @@ //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | //! | `with-time-0_2` | Enable support for the `time` crate. | [time](https://crates.io/crates/time) 0.2 | no | -#![doc(html_root_url = "https://docs.rs/tokio-postgres/0.5")] +#![doc(html_root_url = "https://docs.rs/tokio-postgres/0.6")] #![warn(rust_2018_idioms, clippy::all, missing_docs)] pub use crate::cancel_token::CancelToken; From 5099799166ec44aff6f9a68ee2dc450f4c517df9 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Tue, 1 Dec 2020 19:03:02 +0300 Subject: [PATCH 059/420] return used features --- postgres-native-tls/src/lib.rs | 2 +- tokio-postgres/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres-native-tls/src/lib.rs b/postgres-native-tls/src/lib.rs index 00413c27b..5bded10b4 100644 --- a/postgres-native-tls/src/lib.rs +++ b/postgres-native-tls/src/lib.rs @@ -1,4 +1,4 @@ -//! TLS support for `tokio-postgres` and `postgres` via `native-tls. +//! TLS support for `tokio-postgres` and `postgres` via `native-tls`. //! //! # Examples //! diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 8a29dfd00..90c2b0404 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -103,7 +103,7 @@ //! //! | Feature | Description | Extra dependencies | Default | //! | ------- | ----------- | ------------------ | ------- | -//! | `runtime` | Enable convenience API for the connection process based on the `tokio` crate. | [tokio](https://crates.io/crates/tokio) 0.3 with the `io-util` feature | yes | +//! | `runtime` | Enable convenience API for the connection process based on the `tokio` crate. | [tokio](https://crates.io/crates/tokio) 0.3 with the features `net` and `time` | yes | //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | //! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | From 07d9fb2ed61f8e661ad06a3d587d369c18231503 Mon Sep 17 00:00:00 2001 From: zach-com <54674467+zach-com@users.noreply.github.com> Date: Fri, 11 Dec 2020 13:47:39 -0500 Subject: [PATCH 060/420] Support connection validation with timeout --- postgres/src/client.rs | 5 +++++ tokio-postgres/src/client.rs | 9 +++++++++ tokio-postgres/src/error/mod.rs | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/postgres/src/client.rs b/postgres/src/client.rs index f5637cdbd..001141655 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -413,6 +413,11 @@ impl Client { self.connection.block_on(self.client.simple_query(query)) } + /// Validates connection, timing out after specified duration. + pub fn is_valid(&mut self, timeout: std::time::Duration) -> Result<(), Error> { + self.connection.block_on(self.client.is_valid(timeout)) + } + /// Executes a sequence of SQL statements using the simple query protocol. /// /// Statements should be separated by semicolons. If an error occurs, execution of the sequence will stop at that diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 359a7cd16..090b41480 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -450,6 +450,15 @@ impl Client { self.simple_query_raw(query).await?.try_collect().await } + /// Validates connection, timing out after specified duration. + pub async fn is_valid(&self, timeout: Duration) -> Result<(), Error> { + type SqmResult = Result, Error>; + type SqmTimeout = Result; + let sqm_future = self.simple_query_raw("").await?.try_collect(); + let sqm_timeout: SqmTimeout = tokio::time::timeout(timeout, sqm_future).await; + sqm_timeout.map_err(|_| Error::timeout())?.map(|_| ()) + } + pub(crate) async fn simple_query_raw(&self, query: &str) -> Result { simple_query::simple_query(self.inner(), query).await } diff --git a/tokio-postgres/src/error/mod.rs b/tokio-postgres/src/error/mod.rs index f9335cfe7..529095607 100644 --- a/tokio-postgres/src/error/mod.rs +++ b/tokio-postgres/src/error/mod.rs @@ -354,6 +354,7 @@ enum Kind { RowCount, #[cfg(feature = "runtime")] Connect, + Timeout, } struct ErrorInner { @@ -392,6 +393,7 @@ impl fmt::Display for Error { Kind::RowCount => fmt.write_str("query returned an unexpected number of rows")?, #[cfg(feature = "runtime")] Kind::Connect => fmt.write_str("error connecting to server")?, + Kind::Timeout => fmt.write_str("timeout waiting for server")?, }; if let Some(ref cause) = self.0.cause { write!(fmt, ": {}", cause)?; @@ -491,4 +493,8 @@ impl Error { pub(crate) fn connect(e: io::Error) -> Error { Error::new(Kind::Connect, Some(Box::new(e))) } + + pub(crate) fn timeout() -> Error { + Error::new(Kind::Timeout, None) + } } From c573edbdfb6c83305e59f54dbf045887f85b6577 Mon Sep 17 00:00:00 2001 From: Jeff Davis Date: Tue, 15 Dec 2020 16:50:26 -0800 Subject: [PATCH 061/420] Documentation fixup. --- postgres-protocol/src/escape/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres-protocol/src/escape/mod.rs b/postgres-protocol/src/escape/mod.rs index 4b3b56cd5..0ba7efdca 100644 --- a/postgres-protocol/src/escape/mod.rs +++ b/postgres-protocol/src/escape/mod.rs @@ -1,8 +1,8 @@ //! Provides functions for escaping literals and identifiers for use //! in SQL queries. //! -//! Prefer parameterized queries where possible; see -//! [`Client::query`](crate::Client::query). Do not escape parameters. +//! Prefer parameterized queries where possible. Do not escape +//! parameters in a parameterized query. #[cfg(test)] mod test; From f655c3b74c59144aed35859fecf830e5ce5960db Mon Sep 17 00:00:00 2001 From: zach-com <54674467+zach-com@users.noreply.github.com> Date: Wed, 16 Dec 2020 15:26:06 -0500 Subject: [PATCH 062/420] Address pull request comments --- postgres/src/client.rs | 11 +++++++++-- tokio-postgres/src/bind.rs | 3 ++- tokio-postgres/src/client.rs | 9 --------- tokio-postgres/src/error/mod.rs | 5 ++++- tokio-postgres/src/query.rs | 3 ++- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/postgres/src/client.rs b/postgres/src/client.rs index 001141655..fcd7f772a 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -4,6 +4,7 @@ use crate::{ ToStatement, Transaction, TransactionBuilder, }; use std::task::Poll; +use std::time::Duration; use tokio_postgres::tls::{MakeTlsConnect, TlsConnect}; use tokio_postgres::types::{BorrowToSql, ToSql, Type}; use tokio_postgres::{Error, Row, SimpleQueryMessage, Socket}; @@ -414,8 +415,14 @@ impl Client { } /// Validates connection, timing out after specified duration. - pub fn is_valid(&mut self, timeout: std::time::Duration) -> Result<(), Error> { - self.connection.block_on(self.client.is_valid(timeout)) + pub fn is_valid(&mut self, timeout: Duration) -> Result<(), Error> { + let is_valid = Client::is_valid_inner(&self.client, timeout); + self.connection.block_on(is_valid) + } + + async fn is_valid_inner(client: &tokio_postgres::Client, timeout: Duration) -> Result<(), Error> { + let trivial_query = client.simple_query(""); + tokio::time::timeout(timeout, trivial_query).await?.map(|_| ()) } /// Executes a sequence of SQL statements using the simple query protocol. diff --git a/tokio-postgres/src/bind.rs b/tokio-postgres/src/bind.rs index 9c5c49218..75bd938d9 100644 --- a/tokio-postgres/src/bind.rs +++ b/tokio-postgres/src/bind.rs @@ -20,8 +20,9 @@ where I: IntoIterator, I::IntoIter: ExactSizeIterator, { + type BytesResult = Result; let name = format!("p{}", NEXT_ID.fetch_add(1, Ordering::SeqCst)); - let buf = client.with_buf(|buf| { + let buf = client.with_buf::<_, BytesResult>(|buf| { query::encode_bind(&statement, params, &name, buf)?; frontend::sync(buf); Ok(buf.split().freeze()) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 090b41480..359a7cd16 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -450,15 +450,6 @@ impl Client { self.simple_query_raw(query).await?.try_collect().await } - /// Validates connection, timing out after specified duration. - pub async fn is_valid(&self, timeout: Duration) -> Result<(), Error> { - type SqmResult = Result, Error>; - type SqmTimeout = Result; - let sqm_future = self.simple_query_raw("").await?.try_collect(); - let sqm_timeout: SqmTimeout = tokio::time::timeout(timeout, sqm_future).await; - sqm_timeout.map_err(|_| Error::timeout())?.map(|_| ()) - } - pub(crate) async fn simple_query_raw(&self, query: &str) -> Result { simple_query::simple_query(self.inner(), query).await } diff --git a/tokio-postgres/src/error/mod.rs b/tokio-postgres/src/error/mod.rs index 529095607..bb0dec9a5 100644 --- a/tokio-postgres/src/error/mod.rs +++ b/tokio-postgres/src/error/mod.rs @@ -5,6 +5,7 @@ use postgres_protocol::message::backend::{ErrorFields, ErrorResponseBody}; use std::error::{self, Error as _Error}; use std::fmt; use std::io; +use tokio::time::error::Elapsed; pub use self::sqlstate::*; @@ -493,8 +494,10 @@ impl Error { pub(crate) fn connect(e: io::Error) -> Error { Error::new(Kind::Connect, Some(Box::new(e))) } +} - pub(crate) fn timeout() -> Error { +impl From for Error { + fn from(_e: Elapsed) -> Error { Error::new(Kind::Timeout, None) } } diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index f139ed915..d6179de4d 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -61,7 +61,8 @@ pub async fn query_portal( portal: &Portal, max_rows: i32, ) -> Result { - let buf = client.with_buf(|buf| { + type BytesResult = Result; + let buf = client.with_buf::<_, BytesResult>(|buf| { frontend::execute(portal.name(), max_rows, buf).map_err(Error::encode)?; frontend::sync(buf); Ok(buf.split().freeze()) From ee65811272ff221b6fcf605ef84507a02c2107c1 Mon Sep 17 00:00:00 2001 From: zach-com <54674467+zach-com@users.noreply.github.com> Date: Wed, 16 Dec 2020 15:56:16 -0500 Subject: [PATCH 063/420] Avoid unnecessary function call --- postgres/src/client.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/postgres/src/client.rs b/postgres/src/client.rs index fcd7f772a..f34cffe1d 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -416,13 +416,11 @@ impl Client { /// Validates connection, timing out after specified duration. pub fn is_valid(&mut self, timeout: Duration) -> Result<(), Error> { - let is_valid = Client::is_valid_inner(&self.client, timeout); - self.connection.block_on(is_valid) - } - - async fn is_valid_inner(client: &tokio_postgres::Client, timeout: Duration) -> Result<(), Error> { - let trivial_query = client.simple_query(""); - tokio::time::timeout(timeout, trivial_query).await?.map(|_| ()) + let inner_client = &self.client; + self.connection.block_on(async { + let trivial_query = inner_client.simple_query(""); + tokio::time::timeout(timeout, trivial_query).await?.map(|_| ()) + }) } /// Executes a sequence of SQL statements using the simple query protocol. From ef95f34c34a9a01b8bec6766cc56c34cc9ff6270 Mon Sep 17 00:00:00 2001 From: zach-com <54674467+zach-com@users.noreply.github.com> Date: Wed, 16 Dec 2020 22:17:21 -0500 Subject: [PATCH 064/420] `cargo fmt` --- postgres/src/client.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/postgres/src/client.rs b/postgres/src/client.rs index f34cffe1d..adea5e984 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -419,7 +419,9 @@ impl Client { let inner_client = &self.client; self.connection.block_on(async { let trivial_query = inner_client.simple_query(""); - tokio::time::timeout(timeout, trivial_query).await?.map(|_| ()) + tokio::time::timeout(timeout, trivial_query) + .await? + .map(|_| ()) }) } From 9856c7b87a596023f659f8a281c7ef1caf2a3659 Mon Sep 17 00:00:00 2001 From: zach-com <54674467+zach-com@users.noreply.github.com> Date: Thu, 17 Dec 2020 17:55:22 -0500 Subject: [PATCH 065/420] Replace `impl From` block --- postgres/src/client.rs | 3 ++- tokio-postgres/src/bind.rs | 3 +-- tokio-postgres/src/error/mod.rs | 6 ++---- tokio-postgres/src/query.rs | 3 +-- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/postgres/src/client.rs b/postgres/src/client.rs index adea5e984..050c5b229 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -420,7 +420,8 @@ impl Client { self.connection.block_on(async { let trivial_query = inner_client.simple_query(""); tokio::time::timeout(timeout, trivial_query) - .await? + .await + .map_err(|_| Error::timeout())? .map(|_| ()) }) } diff --git a/tokio-postgres/src/bind.rs b/tokio-postgres/src/bind.rs index 75bd938d9..9c5c49218 100644 --- a/tokio-postgres/src/bind.rs +++ b/tokio-postgres/src/bind.rs @@ -20,9 +20,8 @@ where I: IntoIterator, I::IntoIter: ExactSizeIterator, { - type BytesResult = Result; let name = format!("p{}", NEXT_ID.fetch_add(1, Ordering::SeqCst)); - let buf = client.with_buf::<_, BytesResult>(|buf| { + let buf = client.with_buf(|buf| { query::encode_bind(&statement, params, &name, buf)?; frontend::sync(buf); Ok(buf.split().freeze()) diff --git a/tokio-postgres/src/error/mod.rs b/tokio-postgres/src/error/mod.rs index bb0dec9a5..c5383df92 100644 --- a/tokio-postgres/src/error/mod.rs +++ b/tokio-postgres/src/error/mod.rs @@ -5,7 +5,6 @@ use postgres_protocol::message::backend::{ErrorFields, ErrorResponseBody}; use std::error::{self, Error as _Error}; use std::fmt; use std::io; -use tokio::time::error::Elapsed; pub use self::sqlstate::*; @@ -494,10 +493,9 @@ impl Error { pub(crate) fn connect(e: io::Error) -> Error { Error::new(Kind::Connect, Some(Box::new(e))) } -} -impl From for Error { - fn from(_e: Elapsed) -> Error { + #[doc(hidden)] + pub fn timeout() -> Error { Error::new(Kind::Timeout, None) } } diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index d6179de4d..f139ed915 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -61,8 +61,7 @@ pub async fn query_portal( portal: &Portal, max_rows: i32, ) -> Result { - type BytesResult = Result; - let buf = client.with_buf::<_, BytesResult>(|buf| { + let buf = client.with_buf(|buf| { frontend::execute(portal.name(), max_rows, buf).map_err(Error::encode)?; frontend::sync(buf); Ok(buf.split().freeze()) From 2ab708c4bcd55bed8cee53b88436a5573d071abe Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 17 Dec 2020 20:36:15 -0500 Subject: [PATCH 066/420] minor cleanup --- postgres/src/client.rs | 6 ++++-- tokio-postgres/src/error/mod.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/postgres/src/client.rs b/postgres/src/client.rs index 050c5b229..c052836f0 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -414,14 +414,16 @@ impl Client { self.connection.block_on(self.client.simple_query(query)) } - /// Validates connection, timing out after specified duration. + /// Validates the connection by performing a simple no-op query. + /// + /// If the specified timeout is reached before the backend responds, an error will be returned. pub fn is_valid(&mut self, timeout: Duration) -> Result<(), Error> { let inner_client = &self.client; self.connection.block_on(async { let trivial_query = inner_client.simple_query(""); tokio::time::timeout(timeout, trivial_query) .await - .map_err(|_| Error::timeout())? + .map_err(|_| Error::__private_api_timeout())? .map(|_| ()) }) } diff --git a/tokio-postgres/src/error/mod.rs b/tokio-postgres/src/error/mod.rs index c5383df92..3df529049 100644 --- a/tokio-postgres/src/error/mod.rs +++ b/tokio-postgres/src/error/mod.rs @@ -495,7 +495,7 @@ impl Error { } #[doc(hidden)] - pub fn timeout() -> Error { + pub fn __private_api_timeout() -> Error { Error::new(Kind::Timeout, None) } } From 07aa69febf157492a6bc068ffcf33bc7904983fd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 21 Dec 2020 10:05:20 -0500 Subject: [PATCH 067/420] update rand --- postgres-protocol/Cargo.toml | 2 +- postgres-protocol/src/authentication/sasl.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index 5c7e11478..3ac6acfb3 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -16,6 +16,6 @@ fallible-iterator = "0.2" hmac = "0.10" md5 = "0.7" memchr = "2.0" -rand = "0.7" +rand = "0.8" sha2 = "0.9" stringprep = "0.1" diff --git a/postgres-protocol/src/authentication/sasl.rs b/postgres-protocol/src/authentication/sasl.rs index 416b4b998..d95471133 100644 --- a/postgres-protocol/src/authentication/sasl.rs +++ b/postgres-protocol/src/authentication/sasl.rs @@ -135,7 +135,7 @@ impl ScramSha256 { let mut rng = rand::thread_rng(); let nonce = (0..NONCE_LENGTH) .map(|_| { - let mut v = rng.gen_range(0x21u8, 0x7e); + let mut v = rng.gen_range(0x21u8..0x7e); if v == 0x2c { v = 0x7e } From c395b972a0d65b2587871f8eeafa64dab90aa7a1 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 24 Dec 2020 17:23:11 -0500 Subject: [PATCH 068/420] Create FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..b214efc24 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: [sfackler] From f1729e46367f257607d9b1a9b246acf367514a2c Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Wed, 23 Dec 2020 21:03:15 -0500 Subject: [PATCH 069/420] deps: upgrade to tokio v1.0 ecosystem --- postgres-native-tls/Cargo.toml | 6 ++-- postgres-openssl/Cargo.toml | 6 ++-- postgres-openssl/src/lib.rs | 50 +++++++++++++++++++++++++----- postgres-protocol/Cargo.toml | 2 +- postgres-types/Cargo.toml | 2 +- postgres-types/src/serde_json_1.rs | 1 - postgres/Cargo.toml | 4 +-- postgres/src/copy_out_reader.rs | 2 +- postgres/src/notifications.rs | 9 +++--- tokio-postgres/Cargo.toml | 8 ++--- tokio-postgres/src/binary_copy.rs | 2 +- tokio-postgres/src/copy_in.rs | 1 - 12 files changed, 63 insertions(+), 30 deletions(-) diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index 81dcf29e3..598531ad9 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -18,10 +18,10 @@ runtime = ["tokio-postgres/runtime"] [dependencies] futures = "0.3" native-tls = "0.2" -tokio = "0.3" -tokio-native-tls = "0.2" +tokio = "1.0" +tokio-native-tls = "0.3" tokio-postgres = { version = "0.6.0", path = "../tokio-postgres", default-features = false } [dev-dependencies] -tokio = { version = "0.3", features = ["full"] } +tokio = { version = "1.0", features = ["full"] } postgres = { version = "0.18.0", path = "../postgres" } diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index c825e929d..11fd9f828 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -18,10 +18,10 @@ runtime = ["tokio-postgres/runtime"] [dependencies] futures = "0.3" openssl = "0.10" -tokio = "0.3" -tokio-openssl = "0.5" +tokio = "1.0" +tokio-openssl = "0.6" tokio-postgres = { version = "0.6.0", path = "../tokio-postgres", default-features = false } [dev-dependencies] -tokio = { version = "0.3", features = ["full"] } +tokio = { version = "1.0", features = ["full"] } postgres = { version = "0.18.0", path = "../postgres" } diff --git a/postgres-openssl/src/lib.rs b/postgres-openssl/src/lib.rs index 3780f2082..cad06d486 100644 --- a/postgres-openssl/src/lib.rs +++ b/postgres-openssl/src/lib.rs @@ -48,8 +48,10 @@ use openssl::hash::MessageDigest; use openssl::nid::Nid; #[cfg(feature = "runtime")] use openssl::ssl::SslConnector; -use openssl::ssl::{ConnectConfiguration, SslRef}; -use std::fmt::Debug; +use openssl::ssl::{self, ConnectConfiguration, SslRef}; +use openssl::x509::X509VerifyResult; +use std::error::Error; +use std::fmt::{self, Debug}; use std::future::Future; use std::io; use std::pin::Pin; @@ -57,7 +59,7 @@ use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; -use tokio_openssl::{HandshakeError, SslStream}; +use tokio_openssl::SslStream; use tokio_postgres::tls; #[cfg(feature = "runtime")] use tokio_postgres::tls::MakeTlsConnect; @@ -131,23 +133,55 @@ impl TlsConnector { impl TlsConnect for TlsConnector where - S: AsyncRead + AsyncWrite + Unpin + Debug + 'static + Sync + Send, + S: AsyncRead + AsyncWrite + Unpin + Send + 'static, { type Stream = TlsStream; - type Error = HandshakeError; + type Error = Box; #[allow(clippy::type_complexity)] - type Future = Pin, HandshakeError>> + Send>>; + type Future = Pin, Self::Error>> + Send>>; fn connect(self, stream: S) -> Self::Future { let future = async move { - let stream = tokio_openssl::connect(self.ssl, &self.domain, stream).await?; - Ok(TlsStream(stream)) + let ssl = self.ssl.into_ssl(&self.domain)?; + let mut stream = SslStream::new(ssl, stream)?; + match Pin::new(&mut stream).connect().await { + Ok(()) => Ok(TlsStream(stream)), + Err(error) => Err(Box::new(ConnectError { + error, + verify_result: stream.ssl().verify_result(), + }) as _), + } }; Box::pin(future) } } +#[derive(Debug)] +struct ConnectError { + error: ssl::Error, + verify_result: X509VerifyResult, +} + +impl fmt::Display for ConnectError { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.error, fmt)?; + + if self.verify_result != X509VerifyResult::OK { + fmt.write_str(": ")?; + fmt::Display::fmt(&self.verify_result, fmt)?; + } + + Ok(()) + } +} + +impl Error for ConnectError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + Some(&self.error) + } +} + /// The stream returned by `TlsConnector`. pub struct TlsStream(SslStream); diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index 3ac6acfb3..ed5bca864 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -11,7 +11,7 @@ readme = "../README.md" [dependencies] base64 = "0.13" byteorder = "1.0" -bytes = "0.5" +bytes = "1.0" fallible-iterator = "0.2" hmac = "0.10" md5 = "0.7" diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index c5e706f6e..00babcce2 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -22,7 +22,7 @@ with-uuid-0_8 = ["uuid-08"] with-time-0_2 = ["time-02"] [dependencies] -bytes = "0.5" +bytes = "1.0" fallible-iterator = "0.2" postgres-protocol = { version = "0.5.0", path = "../postgres-protocol" } postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-derive" } diff --git a/postgres-types/src/serde_json_1.rs b/postgres-types/src/serde_json_1.rs index e0fecb496..b98d561d1 100644 --- a/postgres-types/src/serde_json_1.rs +++ b/postgres-types/src/serde_json_1.rs @@ -1,5 +1,4 @@ use crate::{FromSql, IsNull, ToSql, Type}; -use bytes::buf::BufMutExt; use bytes::{BufMut, BytesMut}; use serde_1::{Deserialize, Serialize}; use serde_json_1::Value; diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index b84becd19..52ba17a47 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -31,12 +31,12 @@ with-uuid-0_8 = ["tokio-postgres/with-uuid-0_8"] with-time-0_2 = ["tokio-postgres/with-time-0_2"] [dependencies] -bytes = "0.5" +bytes = "1.0" fallible-iterator = "0.2" futures = "0.3" tokio-postgres = { version = "0.6.0", path = "../tokio-postgres" } -tokio = { version = "0.3", features = ["rt", "time"] } +tokio = { version = "1.0", features = ["rt", "time"] } log = "0.4" [dev-dependencies] diff --git a/postgres/src/copy_out_reader.rs b/postgres/src/copy_out_reader.rs index fd9c27fb0..e8b478d49 100644 --- a/postgres/src/copy_out_reader.rs +++ b/postgres/src/copy_out_reader.rs @@ -46,7 +46,7 @@ impl BufRead for CopyOutReader<'_> { }; } - Ok(self.cur.bytes()) + Ok(&self.cur) } fn consume(&mut self, amt: usize) { diff --git a/postgres/src/notifications.rs b/postgres/src/notifications.rs index 241c95a5d..ea44c31f8 100644 --- a/postgres/src/notifications.rs +++ b/postgres/src/notifications.rs @@ -4,6 +4,7 @@ use crate::connection::ConnectionRef; use crate::{Error, Notification}; use fallible_iterator::FallibleIterator; use futures::{ready, FutureExt}; +use std::pin::Pin; use std::task::Poll; use std::time::Duration; use tokio::time::{self, Instant, Sleep}; @@ -64,7 +65,7 @@ impl<'a> Notifications<'a> { /// This iterator may start returning `Some` after previously returning `None` if more notifications are received. pub fn timeout_iter(&mut self, timeout: Duration) -> TimeoutIter<'_> { TimeoutIter { - delay: self.connection.enter(|| time::sleep(timeout)), + delay: Box::pin(self.connection.enter(|| time::sleep(timeout))), timeout, connection: self.connection.as_ref(), } @@ -124,7 +125,7 @@ impl<'a> FallibleIterator for BlockingIter<'a> { /// A time-limited blocking iterator over pending notifications. pub struct TimeoutIter<'a> { connection: ConnectionRef<'a>, - delay: Sleep, + delay: Pin>, timeout: Duration, } @@ -134,7 +135,7 @@ impl<'a> FallibleIterator for TimeoutIter<'a> { fn next(&mut self) -> Result, Self::Error> { if let Some(notification) = self.connection.notifications_mut().pop_front() { - self.delay.reset(Instant::now() + self.timeout); + self.delay.as_mut().reset(Instant::now() + self.timeout); return Ok(Some(notification)); } @@ -143,7 +144,7 @@ impl<'a> FallibleIterator for TimeoutIter<'a> { self.connection.poll_block_on(|cx, notifications, done| { match notifications.pop_front() { Some(notification) => { - delay.reset(Instant::now() + timeout); + delay.as_mut().reset(Instant::now() + timeout); return Poll::Ready(Ok(Some(notification))); } None if done => return Poll::Ready(Ok(None)), diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index f659663e1..1c82f7da8 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -38,7 +38,7 @@ with-time-0_2 = ["postgres-types/with-time-0_2"] [dependencies] async-trait = "0.1" -bytes = "0.5" +bytes = "1.0" byteorder = "1.0" fallible-iterator = "0.2" futures = "0.3" @@ -50,11 +50,11 @@ phf = "0.8" postgres-protocol = { version = "0.5.0", path = "../postgres-protocol" } postgres-types = { version = "0.1.2", path = "../postgres-types" } socket2 = "0.3" -tokio = { version = "0.3", features = ["io-util"] } -tokio-util = { version = "0.4", features = ["codec"] } +tokio = { version = "1.0", features = ["io-util"] } +tokio-util = { version = "0.6", features = ["codec"] } [dev-dependencies] -tokio = { version = "0.3", features = ["full"] } +tokio = { version = "1.0", features = ["full"] } env_logger = "0.8" criterion = "0.3" diff --git a/tokio-postgres/src/binary_copy.rs b/tokio-postgres/src/binary_copy.rs index 20064c728..3b1e13cd7 100644 --- a/tokio-postgres/src/binary_copy.rs +++ b/tokio-postgres/src/binary_copy.rs @@ -153,7 +153,7 @@ impl Stream for BinaryCopyOutStream { Some(header) => header.has_oids, None => { check_remaining(&chunk, HEADER_LEN)?; - if &chunk.bytes()[..MAGIC.len()] != MAGIC { + if !chunk.chunk().starts_with(MAGIC) { return Poll::Ready(Some(Err(Error::parse(io::Error::new( io::ErrorKind::InvalidData, "invalid magic value", diff --git a/tokio-postgres/src/copy_in.rs b/tokio-postgres/src/copy_in.rs index fc712f6db..bc90e5277 100644 --- a/tokio-postgres/src/copy_in.rs +++ b/tokio-postgres/src/copy_in.rs @@ -2,7 +2,6 @@ use crate::client::{InnerClient, Responses}; use crate::codec::FrontendMessage; use crate::connection::RequestMessages; use crate::{query, slice_iter, Error, Statement}; -use bytes::buf::BufExt; use bytes::{Buf, BufMut, BytesMut}; use futures::channel::mpsc; use futures::future; From 06dcebf248fe067d1ef29ef3427561a4248730f9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 25 Dec 2020 08:51:17 -0500 Subject: [PATCH 070/420] Release postgres-protocol v0.6.0 --- postgres-protocol/CHANGELOG.md | 10 ++++++++++ postgres-protocol/Cargo.toml | 2 +- postgres-types/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/postgres-protocol/CHANGELOG.md b/postgres-protocol/CHANGELOG.md index b476fcabf..4040c3ba2 100644 --- a/postgres-protocol/CHANGELOG.md +++ b/postgres-protocol/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## v0.6.0 - 2020-12-25 + +### Changed + +* Upgraded `bytes`, `hmac`, and `rand`. + +### Added + +* Added `escape::{escape_literal, escape_identifier}`. + ## v0.5.3 - 2020-10-17 ### Changed diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index ed5bca864..6746cfebd 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-protocol" -version = "0.5.3" +version = "0.6.0" authors = ["Steven Fackler "] edition = "2018" description = "Low level Postgres protocol APIs" diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 00babcce2..0707345fa 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -24,7 +24,7 @@ with-time-0_2 = ["time-02"] [dependencies] bytes = "1.0" fallible-iterator = "0.2" -postgres-protocol = { version = "0.5.0", path = "../postgres-protocol" } +postgres-protocol = { version = "0.6.0", path = "../postgres-protocol" } postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-derive" } bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 1c82f7da8..24d962f65 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -47,7 +47,7 @@ parking_lot = "0.11" percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.8" -postgres-protocol = { version = "0.5.0", path = "../postgres-protocol" } +postgres-protocol = { version = "0.6.0", path = "../postgres-protocol" } postgres-types = { version = "0.1.2", path = "../postgres-types" } socket2 = "0.3" tokio = { version = "1.0", features = ["io-util"] } From 71fc3e74bd9bad23c381a3df370c5f5bb23558fe Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 25 Dec 2020 09:01:11 -0500 Subject: [PATCH 071/420] Release postgres-types v0.2.0 --- postgres-types/CHANGELOG.md | 10 ++++ postgres-types/Cargo.toml | 4 +- postgres-types/src/geo_types_04.rs | 78 ------------------------------ postgres-types/src/lib.rs | 2 - postgres/Cargo.toml | 1 - tokio-postgres/Cargo.toml | 4 +- 6 files changed, 12 insertions(+), 87 deletions(-) delete mode 100644 postgres-types/src/geo_types_04.rs diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index 1c267923c..4fb55631b 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## v0.2.0 - 2020-12-25 + +### Changed + +* Upgraded `bytes` to 1.0. + +### Removed + +* Removed support for `geo-types` 0.4. + ## v0.1.3 - 2020-10-17 ### Added diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 0707345fa..40edc621b 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-types" -version = "0.1.3" +version = "0.2.0" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -15,7 +15,6 @@ derive = ["postgres-derive"] with-bit-vec-0_6 = ["bit-vec-06"] with-chrono-0_4 = ["chrono-04"] with-eui48-0_4 = ["eui48-04"] -with-geo-types-0_4 = ["geo-types-04"] with-geo-types-0_6 = ["geo-types-06"] with-serde_json-1 = ["serde-1", "serde_json-1"] with-uuid-0_8 = ["uuid-08"] @@ -30,7 +29,6 @@ postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-deri bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } chrono-04 = { version = "0.4.16", package = "chrono", default-features = false, features = ["clock"], optional = true } eui48-04 = { version = "0.4", package = "eui48", optional = true } -geo-types-04 = { version = "0.4", package = "geo-types", optional = true } geo-types-06 = { version = "0.6", package = "geo-types", optional = true } serde-1 = { version = "1.0", package = "serde", optional = true } serde_json-1 = { version = "1.0", package = "serde_json", optional = true } diff --git a/postgres-types/src/geo_types_04.rs b/postgres-types/src/geo_types_04.rs deleted file mode 100644 index eb8b958eb..000000000 --- a/postgres-types/src/geo_types_04.rs +++ /dev/null @@ -1,78 +0,0 @@ -use bytes::BytesMut; -use fallible_iterator::FallibleIterator; -use geo_types_04::{Coordinate, LineString, Point, Rect}; -use postgres_protocol::types; -use std::error::Error; - -use crate::{FromSql, IsNull, ToSql, Type}; - -impl<'a> FromSql<'a> for Point { - fn from_sql(_: &Type, raw: &[u8]) -> Result> { - let point = types::point_from_sql(raw)?; - Ok(Point::new(point.x(), point.y())) - } - - accepts!(POINT); -} - -impl ToSql for Point { - fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result> { - types::point_to_sql(self.x(), self.y(), out); - Ok(IsNull::No) - } - - accepts!(POINT); - to_sql_checked!(); -} - -impl<'a> FromSql<'a> for Rect { - fn from_sql(_: &Type, raw: &[u8]) -> Result> { - let rect = types::box_from_sql(raw)?; - Ok(Rect { - min: Coordinate { - x: rect.lower_left().x(), - y: rect.lower_left().y(), - }, - max: Coordinate { - x: rect.upper_right().x(), - y: rect.upper_right().y(), - }, - }) - } - - accepts!(BOX); -} - -impl ToSql for Rect { - fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result> { - types::box_to_sql(self.min.x, self.min.y, self.max.x, self.max.y, out); - Ok(IsNull::No) - } - - accepts!(BOX); - to_sql_checked!(); -} - -impl<'a> FromSql<'a> for LineString { - fn from_sql(_: &Type, raw: &[u8]) -> Result> { - let path = types::path_from_sql(raw)?; - let points = path - .points() - .map(|p| Ok(Coordinate { x: p.x(), y: p.y() })) - .collect()?; - Ok(LineString(points)) - } - - accepts!(PATH); -} - -impl ToSql for LineString { - fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result> { - let closed = false; // always encode an open path from LineString - types::path_to_sql(closed, self.0.iter().map(|p| (p.x, p.y)), out)?; - Ok(IsNull::No) - } - - accepts!(PATH); - to_sql_checked!(); -} diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 7e81998b3..2909b81ef 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -191,8 +191,6 @@ mod bit_vec_06; mod chrono_04; #[cfg(feature = "with-eui48-0_4")] mod eui48_04; -#[cfg(feature = "with-geo-types-0_4")] -mod geo_types_04; #[cfg(feature = "with-geo-types-0_6")] mod geo_types_06; #[cfg(feature = "with-serde_json-1")] diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 52ba17a47..70d7ee30d 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -24,7 +24,6 @@ circle-ci = { repository = "sfackler/rust-postgres" } with-bit-vec-0_6 = ["tokio-postgres/with-bit-vec-0_6"] with-chrono-0_4 = ["tokio-postgres/with-chrono-0_4"] with-eui48-0_4 = ["tokio-postgres/with-eui48-0_4"] -with-geo-types-0_4 = ["tokio-postgres/with-geo-types-0_4"] with-geo-types-0_6 = ["tokio-postgres/with-geo-types-0_6"] with-serde_json-1 = ["tokio-postgres/with-serde_json-1"] with-uuid-0_8 = ["tokio-postgres/with-uuid-0_8"] diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 24d962f65..908d1a381 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -30,7 +30,6 @@ runtime = ["tokio/net", "tokio/time"] with-bit-vec-0_6 = ["postgres-types/with-bit-vec-0_6"] with-chrono-0_4 = ["postgres-types/with-chrono-0_4"] with-eui48-0_4 = ["postgres-types/with-eui48-0_4"] -with-geo-types-0_4 = ["postgres-types/with-geo-types-0_4"] with-geo-types-0_6 = ["postgres-types/with-geo-types-0_6"] with-serde_json-1 = ["postgres-types/with-serde_json-1"] with-uuid-0_8 = ["postgres-types/with-uuid-0_8"] @@ -48,7 +47,7 @@ percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.8" postgres-protocol = { version = "0.6.0", path = "../postgres-protocol" } -postgres-types = { version = "0.1.2", path = "../postgres-types" } +postgres-types = { version = "0.2.0", path = "../postgres-types" } socket2 = "0.3" tokio = { version = "1.0", features = ["io-util"] } tokio-util = { version = "0.6", features = ["codec"] } @@ -61,7 +60,6 @@ criterion = "0.3" bit-vec-06 = { version = "0.6", package = "bit-vec" } chrono-04 = { version = "0.4", package = "chrono", default-features = false } eui48-04 = { version = "0.4", package = "eui48" } -geo-types-04 = { version = "0.4", package = "geo-types" } geo-types-06 = { version = "0.6", package = "geo-types" } serde-1 = { version = "1.0", package = "serde" } serde_json-1 = { version = "1.0", package = "serde_json" } From 4fb6fd906f35a4736f50bec65d1e89da55f30a5f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 25 Dec 2020 09:08:20 -0500 Subject: [PATCH 072/420] Release tokio-postgres v0.7.0 --- postgres-native-tls/Cargo.toml | 2 +- postgres-openssl/Cargo.toml | 2 +- postgres/Cargo.toml | 2 +- tokio-postgres/CHANGELOG.md | 13 ++++++++++++- tokio-postgres/Cargo.toml | 2 +- tokio-postgres/src/lib.rs | 2 +- 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index 598531ad9..c55963c53 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -20,7 +20,7 @@ futures = "0.3" native-tls = "0.2" tokio = "1.0" tokio-native-tls = "0.3" -tokio-postgres = { version = "0.6.0", path = "../tokio-postgres", default-features = false } +tokio-postgres = { version = "0.7.0", path = "../tokio-postgres", default-features = false } [dev-dependencies] tokio = { version = "1.0", features = ["full"] } diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index 11fd9f828..ac68c549c 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -20,7 +20,7 @@ futures = "0.3" openssl = "0.10" tokio = "1.0" tokio-openssl = "0.6" -tokio-postgres = { version = "0.6.0", path = "../tokio-postgres", default-features = false } +tokio-postgres = { version = "0.7.0", path = "../tokio-postgres", default-features = false } [dev-dependencies] tokio = { version = "1.0", features = ["full"] } diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 70d7ee30d..ebbb919f2 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -33,7 +33,7 @@ with-time-0_2 = ["tokio-postgres/with-time-0_2"] bytes = "1.0" fallible-iterator = "0.2" futures = "0.3" -tokio-postgres = { version = "0.6.0", path = "../tokio-postgres" } +tokio-postgres = { version = "0.7.0", path = "../tokio-postgres" } tokio = { version = "1.0", features = ["rt", "time"] } log = "0.4" diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 95fd3ed6a..7d513daa2 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,10 +1,21 @@ # Change Log +## v0.7.0 - 2020-12-25 + +### Changed + +* Upgraded to `tokio` 1.0. +* Upgraded to `postgres-types` 0.2. + +### Added + +* Methods taking iterators of `ToSql` values can now take both `&dyn ToSql` and `T: ToSql` values. + ## v0.6.0 - 2020-10-17 ### Changed -* Upgraded to tokio `0.3`. +* Upgraded to `tokio` 0.3. * Added the detail and hint fields to `DbError`'s `Display` implementation. ## v0.5.5 - 2020-07-03 diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 908d1a381..613af127f 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.6.0" +version = "0.7.0" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 90c2b0404..6e73b883d 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -112,7 +112,7 @@ //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | //! | `with-time-0_2` | Enable support for the `time` crate. | [time](https://crates.io/crates/time) 0.2 | no | -#![doc(html_root_url = "https://docs.rs/tokio-postgres/0.6")] +#![doc(html_root_url = "https://docs.rs/tokio-postgres/0.7")] #![warn(rust_2018_idioms, clippy::all, missing_docs)] pub use crate::cancel_token::CancelToken; From de831c3a5384546b0fd6f667dbe7f767fcb6e7a0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 25 Dec 2020 09:14:06 -0500 Subject: [PATCH 073/420] Release postgres v0.19.0 --- postgres-native-tls/Cargo.toml | 2 +- postgres-openssl/Cargo.toml | 2 +- postgres/CHANGELOG.md | 16 ++++++++++++++-- postgres/Cargo.toml | 2 +- postgres/src/lib.rs | 1 - 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index c55963c53..471101af4 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -24,4 +24,4 @@ tokio-postgres = { version = "0.7.0", path = "../tokio-postgres", default-featur [dev-dependencies] tokio = { version = "1.0", features = ["full"] } -postgres = { version = "0.18.0", path = "../postgres" } +postgres = { version = "0.19.0", path = "../postgres" } diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index ac68c549c..cf16055c7 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -24,4 +24,4 @@ tokio-postgres = { version = "0.7.0", path = "../tokio-postgres", default-featur [dev-dependencies] tokio = { version = "1.0", features = ["full"] } -postgres = { version = "0.18.0", path = "../postgres" } +postgres = { version = "0.19.0", path = "../postgres" } diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index 2c9443986..2376068a8 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,6 +1,18 @@ # Change Log -## v0.18.1 - 20201-10-19 +## v0.19.0 - 2020-12-25 + +### Changed + +* Upgraded to `tokio-postgres` 0.7. +* Methods taking iterators of `ToSql` values can now take both `&dyn ToSql` and `T: ToSql` values. + +### Added + +* Added `Client::is_valid` which can be used to check that the connection is still alive with a + timeout. + +## v0.18.1 - 2020-10-19 ### Fixed @@ -69,7 +81,7 @@ * `Client::query_raw` now returns a named type. * `Client::copy_in` and `Client::copy_out` no longer take query parameters as PostgreSQL doesn't support them in COPY queries. - + ### Removed * Removed support for `uuid` 0.7. diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index ebbb919f2..ed63d0c1a 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.18.1" +version = "0.19.0" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" diff --git a/postgres/src/lib.rs b/postgres/src/lib.rs index dc0fd4440..f25fe1175 100644 --- a/postgres/src/lib.rs +++ b/postgres/src/lib.rs @@ -61,7 +61,6 @@ //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | //! | `with-time-0_2` | Enable support for the `time` crate. | [time](https://crates.io/crates/time) 0.2 | no | -#![doc(html_root_url = "https://docs.rs/postgres/0.17")] #![warn(clippy::all, rust_2018_idioms, missing_docs)] pub use fallible_iterator; From eeee279277db483148071e6844e2b5da2adcb3cd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 25 Dec 2020 09:18:12 -0500 Subject: [PATCH 074/420] Relese postgres-native-tls v0.5.0 --- postgres-native-tls/CHANGELOG.md | 6 ++++++ postgres-native-tls/Cargo.toml | 2 +- postgres-native-tls/src/lib.rs | 1 - 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/postgres-native-tls/CHANGELOG.md b/postgres-native-tls/CHANGELOG.md index a840592e3..9eb7ab800 100644 --- a/postgres-native-tls/CHANGELOG.md +++ b/postgres-native-tls/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.5.0 - 2020-12-25 + +### Changed + +* Upgraded to `tokio-postgres` 0.7. + ## v0.4.0 - 2020-10-17 ### Changed diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index 471101af4..8180cd012 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-native-tls" -version = "0.4.0" +version = "0.5.0" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" diff --git a/postgres-native-tls/src/lib.rs b/postgres-native-tls/src/lib.rs index 5bded10b4..70e34812d 100644 --- a/postgres-native-tls/src/lib.rs +++ b/postgres-native-tls/src/lib.rs @@ -45,7 +45,6 @@ //! # Ok(()) //! # } //! ``` -#![doc(html_root_url = "https://docs.rs/postgres-native-tls/0.3")] #![warn(rust_2018_idioms, clippy::all, missing_docs)] use std::future::Future; From 6e9ee0fa8424f4ebca527c4a5d51575ee9d4e1c4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 25 Dec 2020 09:20:58 -0500 Subject: [PATCH 075/420] Release postgres-openssl v0.5.0 --- postgres-openssl/CHANGELOG.md | 6 ++++++ postgres-openssl/Cargo.toml | 2 +- postgres-openssl/src/lib.rs | 1 - 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/postgres-openssl/CHANGELOG.md b/postgres-openssl/CHANGELOG.md index f740828c5..346214ae8 100644 --- a/postgres-openssl/CHANGELOG.md +++ b/postgres-openssl/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.5.0 - 2020-12-25 + +### Changed + +* Upgraded to `tokio-postgres` 0.7. + ## v0.4.0 - 2020-10-17 ### Changed diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index cf16055c7..5738e74d2 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-openssl" -version = "0.4.0" +version = "0.5.0" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" diff --git a/postgres-openssl/src/lib.rs b/postgres-openssl/src/lib.rs index cad06d486..dce3dff5d 100644 --- a/postgres-openssl/src/lib.rs +++ b/postgres-openssl/src/lib.rs @@ -39,7 +39,6 @@ //! # Ok(()) //! # } //! ``` -#![doc(html_root_url = "https://docs.rs/postgres-openssl/0.3")] #![warn(rust_2018_idioms, clippy::all, missing_docs)] #[cfg(feature = "runtime")] From 316c6dc3dca7cdcbe7cd1338f38b1116b35a4e77 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 26 Dec 2020 14:09:58 -0500 Subject: [PATCH 076/420] Update codegen sources to 13.1 --- codegen/src/errcodes.txt | 3 +- codegen/src/pg_range.dat | 2 +- codegen/src/pg_type.dat | 53 ++- postgres-types/src/type_gen.rs | 90 ++++- tokio-postgres/src/error/sqlstate.rs | 559 ++++++++++++++------------- 5 files changed, 410 insertions(+), 297 deletions(-) diff --git a/codegen/src/errcodes.txt b/codegen/src/errcodes.txt index 867e98b69..c79312ed0 100644 --- a/codegen/src/errcodes.txt +++ b/codegen/src/errcodes.txt @@ -2,7 +2,7 @@ # errcodes.txt # PostgreSQL error codes # -# Copyright (c) 2003-2019, PostgreSQL Global Development Group +# Copyright (c) 2003-2020, PostgreSQL Global Development Group # # This list serves as the basis for generating source files containing error # codes. It is kept in a common format to make sure all these source files have @@ -207,6 +207,7 @@ Section: Class 22 - Data Exception 2200S E ERRCODE_INVALID_XML_COMMENT invalid_xml_comment 2200T E ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION invalid_xml_processing_instruction 22030 E ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE duplicate_json_object_key_value +22031 E ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION invalid_argument_for_sql_json_datetime_function 22032 E ERRCODE_INVALID_JSON_TEXT invalid_json_text 22033 E ERRCODE_INVALID_SQL_JSON_SUBSCRIPT invalid_sql_json_subscript 22034 E ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM more_than_one_sql_json_item diff --git a/codegen/src/pg_range.dat b/codegen/src/pg_range.dat index dd9baa267..479754c24 100644 --- a/codegen/src/pg_range.dat +++ b/codegen/src/pg_range.dat @@ -3,7 +3,7 @@ # pg_range.dat # Initial contents of the pg_range system catalog. # -# Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_range.dat diff --git a/codegen/src/pg_type.dat b/codegen/src/pg_type.dat index be49e0011..e8be00083 100644 --- a/codegen/src/pg_type.dat +++ b/codegen/src/pg_type.dat @@ -3,7 +3,7 @@ # pg_type.dat # Initial contents of the pg_type system catalog. # -# Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_type.dat @@ -177,6 +177,10 @@ typtype => 'p', typcategory => 'P', typinput => 'pg_ddl_command_in', typoutput => 'pg_ddl_command_out', typreceive => 'pg_ddl_command_recv', typsend => 'pg_ddl_command_send', typalign => 'ALIGNOF_POINTER' }, +{ oid => '5069', array_type_oid => '271', descr => 'full transaction id', + typname => 'xid8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', + typcategory => 'U', typinput => 'xid8in', typoutput => 'xid8out', + typreceive => 'xid8recv', typsend => 'xid8send', typalign => 'd' }, # OIDS 600 - 699 @@ -215,9 +219,9 @@ { oid => '700', array_type_oid => '1021', descr => 'single-precision floating point number, 4-byte storage', - typname => 'float4', typlen => '4', typbyval => 'FLOAT4PASSBYVAL', - typcategory => 'N', typinput => 'float4in', typoutput => 'float4out', - typreceive => 'float4recv', typsend => 'float4send', typalign => 'i' }, + typname => 'float4', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'float4in', typoutput => 'float4out', typreceive => 'float4recv', + typsend => 'float4send', typalign => 'i' }, { oid => '701', array_type_oid => '1022', descr => 'double-precision floating point number, 8-byte storage', typname => 'float8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', @@ -379,6 +383,11 @@ typname => 'regclass', typlen => '4', typbyval => 't', typcategory => 'N', typinput => 'regclassin', typoutput => 'regclassout', typreceive => 'regclassrecv', typsend => 'regclasssend', typalign => 'i' }, +{ oid => '4191', array_type_oid => '4192', descr => 'registered collation', + typname => 'regcollation', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regcollationin', typoutput => 'regcollationout', + typreceive => 'regcollationrecv', typsend => 'regcollationsend', + typalign => 'i' }, { oid => '2206', array_type_oid => '2211', descr => 'registered type', typname => 'regtype', typlen => '4', typbyval => 't', typcategory => 'N', typinput => 'regtypein', typoutput => 'regtypeout', @@ -451,6 +460,11 @@ typcategory => 'U', typinput => 'txid_snapshot_in', typoutput => 'txid_snapshot_out', typreceive => 'txid_snapshot_recv', typsend => 'txid_snapshot_send', typalign => 'd', typstorage => 'x' }, +{ oid => '5038', array_type_oid => '5039', descr => 'snapshot', + typname => 'pg_snapshot', typlen => '-1', typbyval => 'f', typcategory => 'U', + typinput => 'pg_snapshot_in', typoutput => 'pg_snapshot_out', + typreceive => 'pg_snapshot_recv', typsend => 'pg_snapshot_send', + typalign => 'd', typstorage => 'x' }, # range types { oid => '3904', array_type_oid => '3905', descr => 'range of integers', @@ -546,10 +560,6 @@ typtype => 'p', typcategory => 'P', typinput => 'internal_in', typoutput => 'internal_out', typreceive => '-', typsend => '-', typalign => 'ALIGNOF_POINTER' }, -{ oid => '2282', descr => 'obsolete, deprecated pseudo-type', - typname => 'opaque', typlen => '4', typbyval => 't', typtype => 'p', - typcategory => 'P', typinput => 'opaque_in', typoutput => 'opaque_out', - typreceive => '-', typsend => '-', typalign => 'i' }, { oid => '2283', descr => 'pseudo-type representing a polymorphic base type', typname => 'anyelement', typlen => '4', typbyval => 't', typtype => 'p', typcategory => 'P', typinput => 'anyelement_in', @@ -590,9 +600,34 @@ typoutput => 'table_am_handler_out', typreceive => '-', typsend => '-', typalign => 'i' }, { oid => '3831', - descr => 'pseudo-type representing a polymorphic base type that is a range', + descr => 'pseudo-type representing a range over a polymorphic base type', typname => 'anyrange', typlen => '-1', typbyval => 'f', typtype => 'p', typcategory => 'P', typinput => 'anyrange_in', typoutput => 'anyrange_out', typreceive => '-', typsend => '-', typalign => 'd', typstorage => 'x' }, +{ oid => '5077', + descr => 'pseudo-type representing a polymorphic common type', + typname => 'anycompatible', typlen => '4', typbyval => 't', typtype => 'p', + typcategory => 'P', typinput => 'anycompatible_in', + typoutput => 'anycompatible_out', typreceive => '-', typsend => '-', + typalign => 'i' }, +{ oid => '5078', + descr => 'pseudo-type representing an array of polymorphic common type elements', + typname => 'anycompatiblearray', typlen => '-1', typbyval => 'f', + typtype => 'p', typcategory => 'P', typinput => 'anycompatiblearray_in', + typoutput => 'anycompatiblearray_out', + typreceive => 'anycompatiblearray_recv', typsend => 'anycompatiblearray_send', + typalign => 'd', typstorage => 'x' }, +{ oid => '5079', + descr => 'pseudo-type representing a polymorphic common type that is not an array', + typname => 'anycompatiblenonarray', typlen => '4', typbyval => 't', + typtype => 'p', typcategory => 'P', typinput => 'anycompatiblenonarray_in', + typoutput => 'anycompatiblenonarray_out', typreceive => '-', typsend => '-', + typalign => 'i' }, +{ oid => '5080', + descr => 'pseudo-type representing a range over a polymorphic common type', + typname => 'anycompatiblerange', typlen => '-1', typbyval => 'f', + typtype => 'p', typcategory => 'P', typinput => 'anycompatiblerange_in', + typoutput => 'anycompatiblerange_out', typreceive => '-', typsend => '-', + typalign => 'd', typstorage => 'x' }, ] diff --git a/postgres-types/src/type_gen.rs b/postgres-types/src/type_gen.rs index 8156ccfa5..85978096a 100644 --- a/postgres-types/src/type_gen.rs +++ b/postgres-types/src/type_gen.rs @@ -35,6 +35,7 @@ pub enum Inner { PgNodeTree, JsonArray, TableAmHandler, + Xid8Array, IndexAmHandler, Point, Lseg, @@ -125,7 +126,6 @@ pub enum Inner { Trigger, LanguageHandler, Internal, - Opaque, Anyelement, RecordArray, Anynonarray, @@ -172,7 +172,16 @@ pub enum Inner { RegnamespaceArray, Regrole, RegroleArray, + Regcollation, + RegcollationArray, PgMcvList, + PgSnapshot, + PgSnapshotArray, + Xid8, + Anycompatible, + Anycompatiblearray, + Anycompatiblenonarray, + AnycompatibleRange, Other(Arc), } @@ -201,6 +210,7 @@ impl Inner { 194 => Some(Inner::PgNodeTree), 199 => Some(Inner::JsonArray), 269 => Some(Inner::TableAmHandler), + 271 => Some(Inner::Xid8Array), 325 => Some(Inner::IndexAmHandler), 600 => Some(Inner::Point), 601 => Some(Inner::Lseg), @@ -291,7 +301,6 @@ impl Inner { 2279 => Some(Inner::Trigger), 2280 => Some(Inner::LanguageHandler), 2281 => Some(Inner::Internal), - 2282 => Some(Inner::Opaque), 2283 => Some(Inner::Anyelement), 2287 => Some(Inner::RecordArray), 2776 => Some(Inner::Anynonarray), @@ -338,7 +347,16 @@ impl Inner { 4090 => Some(Inner::RegnamespaceArray), 4096 => Some(Inner::Regrole), 4097 => Some(Inner::RegroleArray), + 4191 => Some(Inner::Regcollation), + 4192 => Some(Inner::RegcollationArray), 5017 => Some(Inner::PgMcvList), + 5038 => Some(Inner::PgSnapshot), + 5039 => Some(Inner::PgSnapshotArray), + 5069 => Some(Inner::Xid8), + 5077 => Some(Inner::Anycompatible), + 5078 => Some(Inner::Anycompatiblearray), + 5079 => Some(Inner::Anycompatiblenonarray), + 5080 => Some(Inner::AnycompatibleRange), _ => None, } } @@ -367,6 +385,7 @@ impl Inner { Inner::PgNodeTree => 194, Inner::JsonArray => 199, Inner::TableAmHandler => 269, + Inner::Xid8Array => 271, Inner::IndexAmHandler => 325, Inner::Point => 600, Inner::Lseg => 601, @@ -457,7 +476,6 @@ impl Inner { Inner::Trigger => 2279, Inner::LanguageHandler => 2280, Inner::Internal => 2281, - Inner::Opaque => 2282, Inner::Anyelement => 2283, Inner::RecordArray => 2287, Inner::Anynonarray => 2776, @@ -504,7 +522,16 @@ impl Inner { Inner::RegnamespaceArray => 4090, Inner::Regrole => 4096, Inner::RegroleArray => 4097, + Inner::Regcollation => 4191, + Inner::RegcollationArray => 4192, Inner::PgMcvList => 5017, + Inner::PgSnapshot => 5038, + Inner::PgSnapshotArray => 5039, + Inner::Xid8 => 5069, + Inner::Anycompatible => 5077, + Inner::Anycompatiblearray => 5078, + Inner::Anycompatiblenonarray => 5079, + Inner::AnycompatibleRange => 5080, Inner::Other(ref u) => u.oid, } } @@ -533,6 +560,7 @@ impl Inner { Inner::PgNodeTree => &Kind::Simple, Inner::JsonArray => &Kind::Array(Type(Inner::Json)), Inner::TableAmHandler => &Kind::Pseudo, + Inner::Xid8Array => &Kind::Array(Type(Inner::Xid8)), Inner::IndexAmHandler => &Kind::Pseudo, Inner::Point => &Kind::Simple, Inner::Lseg => &Kind::Simple, @@ -623,7 +651,6 @@ impl Inner { Inner::Trigger => &Kind::Pseudo, Inner::LanguageHandler => &Kind::Pseudo, Inner::Internal => &Kind::Pseudo, - Inner::Opaque => &Kind::Pseudo, Inner::Anyelement => &Kind::Pseudo, Inner::RecordArray => &Kind::Pseudo, Inner::Anynonarray => &Kind::Pseudo, @@ -670,7 +697,16 @@ impl Inner { Inner::RegnamespaceArray => &Kind::Array(Type(Inner::Regnamespace)), Inner::Regrole => &Kind::Simple, Inner::RegroleArray => &Kind::Array(Type(Inner::Regrole)), + Inner::Regcollation => &Kind::Simple, + Inner::RegcollationArray => &Kind::Array(Type(Inner::Regcollation)), Inner::PgMcvList => &Kind::Simple, + Inner::PgSnapshot => &Kind::Simple, + Inner::PgSnapshotArray => &Kind::Array(Type(Inner::PgSnapshot)), + Inner::Xid8 => &Kind::Simple, + Inner::Anycompatible => &Kind::Pseudo, + Inner::Anycompatiblearray => &Kind::Pseudo, + Inner::Anycompatiblenonarray => &Kind::Pseudo, + Inner::AnycompatibleRange => &Kind::Pseudo, Inner::Other(ref u) => &u.kind, } } @@ -699,6 +735,7 @@ impl Inner { Inner::PgNodeTree => "pg_node_tree", Inner::JsonArray => "_json", Inner::TableAmHandler => "table_am_handler", + Inner::Xid8Array => "_xid8", Inner::IndexAmHandler => "index_am_handler", Inner::Point => "point", Inner::Lseg => "lseg", @@ -789,7 +826,6 @@ impl Inner { Inner::Trigger => "trigger", Inner::LanguageHandler => "language_handler", Inner::Internal => "internal", - Inner::Opaque => "opaque", Inner::Anyelement => "anyelement", Inner::RecordArray => "_record", Inner::Anynonarray => "anynonarray", @@ -836,7 +872,16 @@ impl Inner { Inner::RegnamespaceArray => "_regnamespace", Inner::Regrole => "regrole", Inner::RegroleArray => "_regrole", + Inner::Regcollation => "regcollation", + Inner::RegcollationArray => "_regcollation", Inner::PgMcvList => "pg_mcv_list", + Inner::PgSnapshot => "pg_snapshot", + Inner::PgSnapshotArray => "_pg_snapshot", + Inner::Xid8 => "xid8", + Inner::Anycompatible => "anycompatible", + Inner::Anycompatiblearray => "anycompatiblearray", + Inner::Anycompatiblenonarray => "anycompatiblenonarray", + Inner::AnycompatibleRange => "anycompatiblerange", Inner::Other(ref u) => &u.name, } } @@ -908,6 +953,9 @@ impl Type { /// TABLE_AM_HANDLER pub const TABLE_AM_HANDLER: Type = Type(Inner::TableAmHandler); + /// XID8[] + pub const XID8_ARRAY: Type = Type(Inner::Xid8Array); + /// INDEX_AM_HANDLER - pseudo-type for the result of an index AM handler function pub const INDEX_AM_HANDLER: Type = Type(Inner::IndexAmHandler); @@ -1178,9 +1226,6 @@ impl Type { /// INTERNAL - pseudo-type representing an internal data structure pub const INTERNAL: Type = Type(Inner::Internal); - /// OPAQUE - obsolete, deprecated pseudo-type - pub const OPAQUE: Type = Type(Inner::Opaque); - /// ANYELEMENT - pseudo-type representing a polymorphic base type pub const ANYELEMENT: Type = Type(Inner::Anyelement); @@ -1259,7 +1304,7 @@ impl Type { /// JSONB[] pub const JSONB_ARRAY: Type = Type(Inner::JsonbArray); - /// ANYRANGE - pseudo-type representing a polymorphic base type that is a range + /// ANYRANGE - pseudo-type representing a range over a polymorphic base type pub const ANY_RANGE: Type = Type(Inner::AnyRange); /// EVENT_TRIGGER - pseudo-type for the result of an event trigger function @@ -1319,6 +1364,33 @@ impl Type { /// REGROLE[] pub const REGROLE_ARRAY: Type = Type(Inner::RegroleArray); + /// REGCOLLATION - registered collation + pub const REGCOLLATION: Type = Type(Inner::Regcollation); + + /// REGCOLLATION[] + pub const REGCOLLATION_ARRAY: Type = Type(Inner::RegcollationArray); + /// PG_MCV_LIST - multivariate MCV list pub const PG_MCV_LIST: Type = Type(Inner::PgMcvList); + + /// PG_SNAPSHOT - snapshot + pub const PG_SNAPSHOT: Type = Type(Inner::PgSnapshot); + + /// PG_SNAPSHOT[] + pub const PG_SNAPSHOT_ARRAY: Type = Type(Inner::PgSnapshotArray); + + /// XID8 - full transaction id + pub const XID8: Type = Type(Inner::Xid8); + + /// ANYCOMPATIBLE - pseudo-type representing a polymorphic common type + pub const ANYCOMPATIBLE: Type = Type(Inner::Anycompatible); + + /// ANYCOMPATIBLEARRAY - pseudo-type representing an array of polymorphic common type elements + pub const ANYCOMPATIBLEARRAY: Type = Type(Inner::Anycompatiblearray); + + /// ANYCOMPATIBLENONARRAY - pseudo-type representing a polymorphic common type that is not an array + pub const ANYCOMPATIBLENONARRAY: Type = Type(Inner::Anycompatiblenonarray); + + /// ANYCOMPATIBLERANGE - pseudo-type representing a range over a polymorphic common type + pub const ANYCOMPATIBLE_RANGE: Type = Type(Inner::AnycompatibleRange); } diff --git a/tokio-postgres/src/error/sqlstate.rs b/tokio-postgres/src/error/sqlstate.rs index 013a26472..3a6ea0bdc 100644 --- a/tokio-postgres/src/error/sqlstate.rs +++ b/tokio-postgres/src/error/sqlstate.rs @@ -281,6 +281,10 @@ impl SqlState { /// 22030 pub const DUPLICATE_JSON_OBJECT_KEY_VALUE: SqlState = SqlState(Cow::Borrowed("22030")); + /// 22031 + pub const INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION: SqlState = + SqlState(Cow::Borrowed("22031")); + /// 22032 pub const INVALID_JSON_TEXT: SqlState = SqlState(Cow::Borrowed("22032")); @@ -826,318 +830,319 @@ impl SqlState { #[rustfmt::skip] static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ::phf::Map { - key: 3213172566270843353, + key: 732231254413039614, disps: ::phf::Slice::Static(&[ - (3, 46), (0, 6), - (0, 39), - (0, 0), - (0, 192), - (0, 49), - (0, 17), - (1, 138), - (0, 2), - (0, 117), - (0, 0), - (0, 33), - (16, 241), - (0, 20), - (2, 148), (0, 0), + (0, 218), + (0, 11), + (0, 31), + (0, 91), + (0, 55), + (0, 77), + (0, 72), (0, 1), - (1, 3), - (0, 27), - (0, 21), - (1, 75), - (13, 187), - (0, 3), - (0, 42), - (0, 12), - (0, 82), - (3, 253), - (0, 219), - (0, 6), - (4, 206), - (2, 16), - (5, 67), - (3, 15), - (0, 76), - (0, 57), - (5, 203), - (22, 134), - (1, 27), + (0, 73), + (1, 159), + (4, 4), + (0, 18), + (2, 100), + (0, 19), + (0, 16), + (0, 22), + (0, 51), (0, 0), - (1, 113), (0, 0), + (1, 2), + (2, 177), + (0, 10), + (1, 192), (0, 0), - (5, 11), - (0, 45), - (0, 62), - (0, 26), - (1, 158), - (21, 1), - (0, 4), - (5, 64), - (0, 77), - (1, 189), + (5, 245), + (0, 106), + (6, 243), + (47, 195), + (0, 146), + (4, 154), + (0, 2), + (4, 78), + (0, 196), + (0, 8), + (2, 146), + (0, 15), + (0, 170), + (0, 5), + (10, 18), + (0, 30), + (0, 33), + (0, 2), + (0, 0), + (47, 181), + (0, 144), + (39, 231), + (39, 173), + (0, 57), + (0, 7), + (1, 154), ]), entries: ::phf::Slice::Static(&[ - ("38002", SqlState::E_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED), - ("XX002", SqlState::INDEX_CORRUPTED), - ("HV091", SqlState::FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER), - ("42P08", SqlState::AMBIGUOUS_PARAMETER), - ("44000", SqlState::WITH_CHECK_OPTION_VIOLATION), - ("2202E", SqlState::ARRAY_ELEMENT_ERROR), - ("25008", SqlState::HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL), - ("0Z000", SqlState::DIAGNOSTICS_EXCEPTION), - ("58P01", SqlState::UNDEFINED_FILE), - ("2201W", SqlState::INVALID_ROW_COUNT_IN_LIMIT_CLAUSE), - ("42P05", SqlState::DUPLICATE_PSTATEMENT), - ("P0001", SqlState::RAISE_EXCEPTION), - ("08P01", SqlState::PROTOCOL_VIOLATION), + ("22P04", SqlState::BAD_COPY_FILE_FORMAT), + ("39001", SqlState::E_R_I_E_INVALID_SQLSTATE_RETURNED), + ("2201F", SqlState::INVALID_ARGUMENT_FOR_POWER_FUNCTION), ("54000", SqlState::PROGRAM_LIMIT_EXCEEDED), - ("HV014", SqlState::FDW_TOO_MANY_HANDLES), - ("2F003", SqlState::S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), - ("53200", SqlState::OUT_OF_MEMORY), - ("2200C", SqlState::INVALID_USE_OF_ESCAPE_CHARACTER), - ("25000", SqlState::INVALID_TRANSACTION_STATE), - ("27000", SqlState::TRIGGERED_DATA_CHANGE_VIOLATION), - ("42602", SqlState::INVALID_NAME), - ("08000", SqlState::CONNECTION_EXCEPTION), - ("57P03", SqlState::CANNOT_CONNECT_NOW), - ("2D000", SqlState::INVALID_TRANSACTION_TERMINATION), - ("3B001", SqlState::S_E_INVALID_SPECIFICATION), - ("HV005", SqlState::FDW_COLUMN_NAME_NOT_FOUND), - ("42501", SqlState::INSUFFICIENT_PRIVILEGE), - ("22018", SqlState::INVALID_CHARACTER_VALUE_FOR_CAST), - ("2203D", SqlState::TOO_MANY_JSON_ARRAY_ELEMENTS), - ("P0003", SqlState::TOO_MANY_ROWS), - ("2F005", SqlState::S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), - ("HV002", SqlState::FDW_DYNAMIC_PARAMETER_VALUE_NEEDED), - ("23505", SqlState::UNIQUE_VIOLATION), - ("38004", SqlState::E_R_E_READING_SQL_DATA_NOT_PERMITTED), - ("22019", SqlState::INVALID_ESCAPE_CHARACTER), - ("2200S", SqlState::INVALID_XML_COMMENT), - ("22030", SqlState::DUPLICATE_JSON_OBJECT_KEY_VALUE), - ("2200G", SqlState::MOST_SPECIFIC_TYPE_MISMATCH), - ("25007", SqlState::SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED), - ("HV024", SqlState::FDW_INVALID_ATTRIBUTE_VALUE), - ("25P03", SqlState::IDLE_IN_TRANSACTION_SESSION_TIMEOUT), - ("0LP01", SqlState::INVALID_GRANT_OPERATION), - ("34000", SqlState::INVALID_CURSOR_NAME), - ("57P02", SqlState::CRASH_SHUTDOWN), - ("22012", SqlState::DIVISION_BY_ZERO), - ("42723", SqlState::DUPLICATE_FUNCTION), - ("22004", SqlState::NULL_VALUE_NOT_ALLOWED), - ("2201X", SqlState::INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE), - ("57000", SqlState::OPERATOR_INTERVENTION), - ("HV008", SqlState::FDW_INVALID_COLUMN_NUMBER), - ("HV00P", SqlState::FDW_NO_SCHEMAS), - ("2203F", SqlState::SQL_JSON_SCALAR_REQUIRED), - ("2201G", SqlState::INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION), - ("23001", SqlState::RESTRICT_VIOLATION), - ("23514", SqlState::CHECK_VIOLATION), - ("42939", SqlState::RESERVED_NAME), - ("25004", SqlState::INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION), - ("HV00K", SqlState::FDW_REPLY_HANDLE), - ("22P06", SqlState::NONSTANDARD_USE_OF_ESCAPE_CHARACTER), - ("53100", SqlState::DISK_FULL), - ("28000", SqlState::INVALID_AUTHORIZATION_SPECIFICATION), - ("03000", SqlState::SQL_STATEMENT_NOT_YET_COMPLETE), - ("72000", SqlState::SNAPSHOT_TOO_OLD), - ("22003", SqlState::NUMERIC_VALUE_OUT_OF_RANGE), - ("25002", SqlState::BRANCH_TRANSACTION_ALREADY_ACTIVE), - ("40002", SqlState::T_R_INTEGRITY_CONSTRAINT_VIOLATION), - ("22013", SqlState::INVALID_PRECEDING_OR_FOLLOWING_SIZE), - ("HV00R", SqlState::FDW_TABLE_NOT_FOUND), - ("2200L", SqlState::NOT_AN_XML_DOCUMENT), - ("25005", SqlState::NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION), - ("25P02", SqlState::IN_FAILED_SQL_TRANSACTION), - ("22007", SqlState::INVALID_DATETIME_FORMAT), - ("26000", SqlState::INVALID_SQL_STATEMENT_NAME), - ("23000", SqlState::INTEGRITY_CONSTRAINT_VIOLATION), - ("42P10", SqlState::INVALID_COLUMN_REFERENCE), - ("2200D", SqlState::INVALID_ESCAPE_OCTET), - ("HV004", SqlState::FDW_INVALID_DATA_TYPE), - ("22005", SqlState::ERROR_IN_ASSIGNMENT), - ("P0002", SqlState::NO_DATA_FOUND), - ("22036", SqlState::NON_NUMERIC_SQL_JSON_ITEM), - ("58030", SqlState::IO_ERROR), - ("HV00Q", SqlState::FDW_SCHEMA_NOT_FOUND), - ("F0001", SqlState::LOCK_FILE_EXISTS), - ("01003", SqlState::WARNING_NULL_VALUE_ELIMINATED_IN_SET_FUNCTION), + ("2200T", SqlState::INVALID_XML_PROCESSING_INSTRUCTION), ("01000", SqlState::WARNING), - ("22032", SqlState::INVALID_JSON_TEXT), - ("2B000", SqlState::DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST), + ("02000", SqlState::NO_DATA), ("40003", SqlState::T_R_STATEMENT_COMPLETION_UNKNOWN), - ("53400", SqlState::CONFIGURATION_LIMIT_EXCEEDED), - ("2F004", SqlState::S_R_E_READING_SQL_DATA_NOT_PERMITTED), - ("39P03", SqlState::E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED), - ("42846", SqlState::CANNOT_COERCE), - ("39P02", SqlState::E_R_I_E_SRF_PROTOCOL_VIOLATED), - ("23503", SqlState::FOREIGN_KEY_VIOLATION), + ("42702", SqlState::AMBIGUOUS_COLUMN), + ("HV000", SqlState::FDW_ERROR), + ("2203A", SqlState::SQL_JSON_MEMBER_NOT_FOUND), + ("22021", SqlState::CHARACTER_NOT_IN_REPERTOIRE), + ("HV006", SqlState::FDW_INVALID_DATA_TYPE_DESCRIPTORS), + ("40000", SqlState::TRANSACTION_ROLLBACK), ("57P01", SqlState::ADMIN_SHUTDOWN), - ("55P04", SqlState::UNSAFE_NEW_ENUM_VALUE_USAGE), - ("42P19", SqlState::INVALID_RECURSION), - ("53300", SqlState::TOO_MANY_CONNECTIONS), - ("42804", SqlState::DATATYPE_MISMATCH), - ("22015", SqlState::INTERVAL_FIELD_OVERFLOW), - ("0A000", SqlState::FEATURE_NOT_SUPPORTED), - ("0F000", SqlState::LOCATOR_EXCEPTION), - ("42710", SqlState::DUPLICATE_OBJECT), + ("22034", SqlState::MORE_THAN_ONE_SQL_JSON_ITEM), + ("54023", SqlState::TOO_MANY_ARGUMENTS), + ("22027", SqlState::TRIM_ERROR), ("2203C", SqlState::SQL_JSON_OBJECT_NOT_FOUND), - ("P0004", SqlState::ASSERT_FAILURE), - ("22025", SqlState::INVALID_ESCAPE_SEQUENCE), - ("42P17", SqlState::INVALID_OBJECT_DEFINITION), - ("XX000", SqlState::INTERNAL_ERROR), - ("22009", SqlState::INVALID_TIME_ZONE_DISPLACEMENT_VALUE), - ("HV00J", SqlState::FDW_OPTION_NAME_NOT_FOUND), + ("22P06", SqlState::NONSTANDARD_USE_OF_ESCAPE_CHARACTER), + ("72000", SqlState::SNAPSHOT_TOO_OLD), + ("25004", SqlState::INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION), + ("2BP01", SqlState::DEPENDENT_OBJECTS_STILL_EXIST), ("42P11", SqlState::INVALID_CURSOR_DEFINITION), - ("25P01", SqlState::NO_ACTIVE_SQL_TRANSACTION), - ("22034", SqlState::MORE_THAN_ONE_SQL_JSON_ITEM), - ("HV010", SqlState::FDW_FUNCTION_SEQUENCE_ERROR), - ("22P01", SqlState::FLOATING_POINT_EXCEPTION), - ("2F000", SqlState::SQL_ROUTINE_EXCEPTION), - ("21000", SqlState::CARDINALITY_VIOLATION), - ("40001", SqlState::T_R_SERIALIZATION_FAILURE), - ("01P01", SqlState::WARNING_DEPRECATED_FEATURE), - ("22026", SqlState::STRING_DATA_LENGTH_MISMATCH), + ("HV00J", SqlState::FDW_OPTION_NAME_NOT_FOUND), + ("42804", SqlState::DATATYPE_MISMATCH), + ("39004", SqlState::E_R_I_E_NULL_VALUE_NOT_ALLOWED), + ("42703", SqlState::UNDEFINED_COLUMN), + ("2203E", SqlState::TOO_MANY_JSON_OBJECT_MEMBERS), ("42P12", SqlState::INVALID_DATABASE_DEFINITION), - ("42704", SqlState::UNDEFINED_OBJECT), - ("42P04", SqlState::DUPLICATE_DATABASE), - ("HV000", SqlState::FDW_ERROR), - ("42P14", SqlState::INVALID_PSTATEMENT_DEFINITION), - ("HV00M", SqlState::FDW_UNABLE_TO_CREATE_REPLY), - ("42701", SqlState::DUPLICATE_COLUMN), - ("55P02", SqlState::CANT_CHANGE_RUNTIME_PARAM), - ("HV090", SqlState::FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH), - ("XX001", SqlState::DATA_CORRUPTED), - ("22038", SqlState::SINGLETON_SQL_JSON_ITEM_REQUIRED), - ("58P02", SqlState::DUPLICATE_FILE), + ("23503", SqlState::FOREIGN_KEY_VIOLATION), + ("25003", SqlState::INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION), + ("22P03", SqlState::INVALID_BINARY_REPRESENTATION), + ("40002", SqlState::T_R_INTEGRITY_CONSTRAINT_VIOLATION), + ("58030", SqlState::IO_ERROR), + ("01004", SqlState::WARNING_STRING_DATA_RIGHT_TRUNCATION), + ("22019", SqlState::INVALID_ESCAPE_CHARACTER), + ("42P20", SqlState::WINDOWING_ERROR), + ("3D000", SqlState::INVALID_CATALOG_NAME), ("22001", SqlState::STRING_DATA_RIGHT_TRUNCATION), - ("08003", SqlState::CONNECTION_DOES_NOT_EXIST), - ("39000", SqlState::EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), - ("HV00B", SqlState::FDW_INVALID_HANDLE), - ("54011", SqlState::TOO_MANY_COLUMNS), - ("0Z002", SqlState::STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER), - ("2203E", SqlState::TOO_MANY_JSON_OBJECT_MEMBERS), - ("23P01", SqlState::EXCLUSION_VIOLATION), - ("HV006", SqlState::FDW_INVALID_DATA_TYPE_DESCRIPTORS), - ("39004", SqlState::E_R_I_E_NULL_VALUE_NOT_ALLOWED), - ("HV009", SqlState::FDW_INVALID_USE_OF_NULL_POINTER), - ("22035", SqlState::NO_SQL_JSON_ITEM), - ("HV001", SqlState::FDW_OUT_OF_MEMORY), - ("3F000", SqlState::INVALID_SCHEMA_NAME), - ("0B000", SqlState::INVALID_TRANSACTION_INITIATION), - ("42830", SqlState::INVALID_FOREIGN_KEY), - ("01007", SqlState::WARNING_PRIVILEGE_NOT_GRANTED), - ("2201F", SqlState::INVALID_ARGUMENT_FOR_POWER_FUNCTION), - ("54023", SqlState::TOO_MANY_ARGUMENTS), - ("09000", SqlState::TRIGGERED_ACTION_EXCEPTION), - ("2200H", SqlState::SEQUENCE_GENERATOR_LIMIT_EXCEEDED), - ("428C9", SqlState::GENERATED_ALWAYS), - ("53000", SqlState::INSUFFICIENT_RESOURCES), - ("42P09", SqlState::AMBIGUOUS_ALIAS), - ("08006", SqlState::CONNECTION_FAILURE), - ("22039", SqlState::SQL_JSON_ARRAY_NOT_FOUND), - ("54001", SqlState::STATEMENT_TOO_COMPLEX), - ("2203A", SqlState::SQL_JSON_MEMBER_NOT_FOUND), - ("23502", SqlState::NOT_NULL_VIOLATION), - ("22008", SqlState::DATETIME_FIELD_OVERFLOW), ("F0000", SqlState::CONFIG_FILE_ERROR), - ("3B000", SqlState::SAVEPOINT_EXCEPTION), - ("2BP01", SqlState::DEPENDENT_OBJECTS_STILL_EXIST), - ("2202H", SqlState::INVALID_TABLESAMPLE_ARGUMENT), - ("38001", SqlState::E_R_E_CONTAINING_SQL_NOT_PERMITTED), - ("01004", SqlState::WARNING_STRING_DATA_RIGHT_TRUNCATION), + ("25005", SqlState::NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION), + ("42883", SqlState::UNDEFINED_FUNCTION), + ("42P06", SqlState::DUPLICATE_SCHEMA), + ("42P17", SqlState::INVALID_OBJECT_DEFINITION), + ("HV002", SqlState::FDW_DYNAMIC_PARAMETER_VALUE_NEEDED), + ("0F001", SqlState::L_E_INVALID_SPECIFICATION), ("57014", SqlState::QUERY_CANCELED), - ("55000", SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE), - ("40000", SqlState::TRANSACTION_ROLLBACK), - ("HV00L", SqlState::FDW_UNABLE_TO_CREATE_EXECUTION), ("22033", SqlState::INVALID_SQL_JSON_SUBSCRIPT), - ("02000", SqlState::NO_DATA), - ("2200T", SqlState::INVALID_XML_PROCESSING_INSTRUCTION), - ("3D000", SqlState::INVALID_CATALOG_NAME), - ("2200M", SqlState::INVALID_XML_DOCUMENT), + ("2F004", SqlState::S_R_E_READING_SQL_DATA_NOT_PERMITTED), ("42611", SqlState::INVALID_COLUMN_DEFINITION), - ("2F002", SqlState::S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED), - ("22P05", SqlState::UNTRANSLATABLE_CHARACTER), - ("42883", SqlState::UNDEFINED_FUNCTION), + ("42939", SqlState::RESERVED_NAME), + ("0P000", SqlState::INVALID_ROLE_SPECIFICATION), + ("53200", SqlState::OUT_OF_MEMORY), + ("42809", SqlState::WRONG_OBJECT_TYPE), + ("2202H", SqlState::INVALID_TABLESAMPLE_ARGUMENT), + ("42P16", SqlState::INVALID_TABLE_DEFINITION), + ("24000", SqlState::INVALID_CURSOR_STATE), + ("42P13", SqlState::INVALID_FUNCTION_DEFINITION), + ("22007", SqlState::INVALID_DATETIME_FORMAT), + ("2D000", SqlState::INVALID_TRANSACTION_TERMINATION), + ("53100", SqlState::DISK_FULL), + ("P0003", SqlState::TOO_MANY_ROWS), ("22016", SqlState::INVALID_ARGUMENT_FOR_NTH_VALUE), - ("22027", SqlState::TRIM_ERROR), - ("39P01", SqlState::E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), - ("0L000", SqlState::INVALID_GRANTOR), - ("42725", SqlState::AMBIGUOUS_FUNCTION), + ("2F002", SqlState::S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED), + ("42830", SqlState::INVALID_FOREIGN_KEY), + ("27000", SqlState::TRIGGERED_DATA_CHANGE_VIOLATION), + ("0Z002", SqlState::STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER), + ("53000", SqlState::INSUFFICIENT_RESOURCES), + ("23502", SqlState::NOT_NULL_VIOLATION), + ("XX000", SqlState::INTERNAL_ERROR), + ("58P01", SqlState::UNDEFINED_FILE), ("42601", SqlState::SYNTAX_ERROR), - ("22002", SqlState::NULL_VALUE_NO_INDICATOR_PARAMETER), - ("42702", SqlState::AMBIGUOUS_COLUMN), - ("22024", SqlState::UNTERMINATED_C_STRING), - ("22023", SqlState::INVALID_PARAMETER_VALUE), - ("22P03", SqlState::INVALID_BINARY_REPRESENTATION), + ("02001", SqlState::NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED), + ("42P09", SqlState::AMBIGUOUS_ALIAS), + ("22P02", SqlState::INVALID_TEXT_REPRESENTATION), + ("55P02", SqlState::CANT_CHANGE_RUNTIME_PARAM), + ("2F003", SqlState::S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), + ("53300", SqlState::TOO_MANY_CONNECTIONS), + ("25P02", SqlState::IN_FAILED_SQL_TRANSACTION), + ("42P03", SqlState::DUPLICATE_CURSOR), + ("XX002", SqlState::INDEX_CORRUPTED), ("22010", SqlState::INVALID_INDICATOR_PARAMETER_VALUE), - ("42P16", SqlState::INVALID_TABLE_DEFINITION), - ("0P000", SqlState::INVALID_ROLE_SPECIFICATION), - ("2203B", SqlState::SQL_JSON_NUMBER_NOT_FOUND), - ("55006", SqlState::OBJECT_IN_USE), - ("42P13", SqlState::INVALID_FUNCTION_DEFINITION), - ("42803", SqlState::GROUPING_ERROR), - ("22021", SqlState::CHARACTER_NOT_IN_REPERTOIRE), - ("08004", SqlState::SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION), - ("42P15", SqlState::INVALID_SCHEMA_DEFINITION), + ("01006", SqlState::WARNING_PRIVILEGE_NOT_REVOKED), + ("3B001", SqlState::S_E_INVALID_SPECIFICATION), + ("42P21", SqlState::COLLATION_MISMATCH), + ("42P07", SqlState::DUPLICATE_TABLE), + ("22013", SqlState::INVALID_PRECEDING_OR_FOLLOWING_SIZE), + ("0Z000", SqlState::DIAGNOSTICS_EXCEPTION), + ("55P04", SqlState::UNSAFE_NEW_ENUM_VALUE_USAGE), + ("42000", SqlState::SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION), + ("XX001", SqlState::DATA_CORRUPTED), + ("25008", SqlState::HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL), + ("HV00M", SqlState::FDW_UNABLE_TO_CREATE_REPLY), + ("39000", SqlState::EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + ("22032", SqlState::INVALID_JSON_TEXT), ("25006", SqlState::READ_ONLY_SQL_TRANSACTION), - ("42P02", SqlState::UNDEFINED_PARAMETER), - ("2201E", SqlState::INVALID_ARGUMENT_FOR_LOG), + ("01P01", SqlState::WARNING_DEPRECATED_FEATURE), + ("42725", SqlState::AMBIGUOUS_FUNCTION), + ("42602", SqlState::INVALID_NAME), + ("2201W", SqlState::INVALID_ROW_COUNT_IN_LIMIT_CLAUSE), + ("42P05", SqlState::DUPLICATE_PSTATEMENT), + ("HV021", SqlState::FDW_INCONSISTENT_DESCRIPTOR_INFORMATION), + ("57P03", SqlState::CANNOT_CONNECT_NOW), + ("58P02", SqlState::DUPLICATE_FILE), ("42P22", SqlState::INDETERMINATE_COLLATION), - ("0F001", SqlState::L_E_INVALID_SPECIFICATION), - ("2201B", SqlState::INVALID_REGULAR_EXPRESSION), + ("0B000", SqlState::INVALID_TRANSACTION_INITIATION), + ("0100C", SqlState::WARNING_DYNAMIC_RESULT_SETS_RETURNED), + ("22015", SqlState::INTERVAL_FIELD_OVERFLOW), + ("2200S", SqlState::INVALID_XML_COMMENT), + ("2200M", SqlState::INVALID_XML_DOCUMENT), + ("HV001", SqlState::FDW_OUT_OF_MEMORY), + ("25001", SqlState::ACTIVE_SQL_TRANSACTION), + ("22002", SqlState::NULL_VALUE_NO_INDICATOR_PARAMETER), + ("2F005", SqlState::S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), + ("428C9", SqlState::GENERATED_ALWAYS), + ("25P01", SqlState::NO_ACTIVE_SQL_TRANSACTION), + ("HV091", SqlState::FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER), + ("2200C", SqlState::INVALID_USE_OF_ESCAPE_CHARACTER), + ("HV008", SqlState::FDW_INVALID_COLUMN_NUMBER), + ("2200F", SqlState::ZERO_LENGTH_CHARACTER_STRING), + ("54001", SqlState::STATEMENT_TOO_COMPLEX), + ("42712", SqlState::DUPLICATE_ALIAS), + ("HV00A", SqlState::FDW_INVALID_STRING_FORMAT), + ("42710", SqlState::DUPLICATE_OBJECT), + ("54011", SqlState::TOO_MANY_COLUMNS), + ("42P19", SqlState::INVALID_RECURSION), + ("42501", SqlState::INSUFFICIENT_PRIVILEGE), + ("57000", SqlState::OPERATOR_INTERVENTION), + ("25002", SqlState::BRANCH_TRANSACTION_ALREADY_ACTIVE), + ("22039", SqlState::SQL_JSON_ARRAY_NOT_FOUND), + ("P0002", SqlState::NO_DATA_FOUND), + ("2201G", SqlState::INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION), + ("22012", SqlState::DIVISION_BY_ZERO), + ("42P10", SqlState::INVALID_COLUMN_REFERENCE), + ("HV00B", SqlState::FDW_INVALID_HANDLE), + ("38003", SqlState::E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), + ("25P03", SqlState::IDLE_IN_TRANSACTION_SESSION_TIMEOUT), + ("F0001", SqlState::LOCK_FILE_EXISTS), ("08001", SqlState::SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION), - ("42P07", SqlState::DUPLICATE_TABLE), - ("02001", SqlState::NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED), + ("2203D", SqlState::TOO_MANY_JSON_ARRAY_ELEMENTS), + ("P0000", SqlState::PLPGSQL_ERROR), + ("28000", SqlState::INVALID_AUTHORIZATION_SPECIFICATION), + ("2200D", SqlState::INVALID_ESCAPE_OCTET), + ("55P03", SqlState::LOCK_NOT_AVAILABLE), + ("23505", SqlState::UNIQUE_VIOLATION), + ("39P01", SqlState::E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + ("44000", SqlState::WITH_CHECK_OPTION_VIOLATION), + ("22030", SqlState::DUPLICATE_JSON_OBJECT_KEY_VALUE), + ("P0004", SqlState::ASSERT_FAILURE), + ("2200G", SqlState::MOST_SPECIFIC_TYPE_MISMATCH), + ("2F000", SqlState::SQL_ROUTINE_EXCEPTION), + ("26000", SqlState::INVALID_SQL_STATEMENT_NAME), + ("2202G", SqlState::INVALID_TABLESAMPLE_REPEAT), + ("22003", SqlState::NUMERIC_VALUE_OUT_OF_RANGE), + ("21000", SqlState::CARDINALITY_VIOLATION), + ("0A000", SqlState::FEATURE_NOT_SUPPORTED), + ("HV014", SqlState::FDW_TOO_MANY_HANDLES), + ("08004", SqlState::SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION), + ("38001", SqlState::E_R_E_CONTAINING_SQL_NOT_PERMITTED), + ("01003", SqlState::WARNING_NULL_VALUE_ELIMINATED_IN_SET_FUNCTION), + ("08007", SqlState::TRANSACTION_RESOLUTION_UNKNOWN), + ("HV00D", SqlState::FDW_INVALID_OPTION_NAME), + ("38002", SqlState::E_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED), + ("HV00K", SqlState::FDW_REPLY_HANDLE), + ("23P01", SqlState::EXCLUSION_VIOLATION), + ("42P04", SqlState::DUPLICATE_DATABASE), + ("22025", SqlState::INVALID_ESCAPE_SEQUENCE), + ("HV007", SqlState::FDW_INVALID_COLUMN_NAME), + ("34000", SqlState::INVALID_CURSOR_NAME), + ("HV00L", SqlState::FDW_UNABLE_TO_CREATE_EXECUTION), + ("HV009", SqlState::FDW_INVALID_USE_OF_NULL_POINTER), + ("38000", SqlState::EXTERNAL_ROUTINE_EXCEPTION), + ("2B000", SqlState::DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST), + ("00000", SqlState::SUCCESSFUL_COMPLETION), ("58000", SqlState::SYSTEM_ERROR), - ("42000", SqlState::SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION), - ("42622", SqlState::NAME_TOO_LONG), + ("2201E", SqlState::INVALID_ARGUMENT_FOR_LOG), + ("HV024", SqlState::FDW_INVALID_ATTRIBUTE_VALUE), + ("2200L", SqlState::NOT_AN_XML_DOCUMENT), + ("2203B", SqlState::SQL_JSON_NUMBER_NOT_FOUND), + ("42846", SqlState::CANNOT_COERCE), + ("22035", SqlState::NO_SQL_JSON_ITEM), + ("HV005", SqlState::FDW_COLUMN_NAME_NOT_FOUND), ("20000", SqlState::CASE_NOT_FOUND), - ("08007", SqlState::TRANSACTION_RESOLUTION_UNKNOWN), - ("22022", SqlState::INDICATOR_OVERFLOW), - ("42P18", SqlState::INDETERMINATE_DATATYPE), + ("40001", SqlState::T_R_SERIALIZATION_FAILURE), + ("22000", SqlState::DATA_EXCEPTION), + ("22038", SqlState::SINGLETON_SQL_JSON_ITEM_REQUIRED), + ("42P14", SqlState::INVALID_PSTATEMENT_DEFINITION), + ("39P02", SqlState::E_R_I_E_SRF_PROTOCOL_VIOLATED), ("01008", SqlState::WARNING_IMPLICIT_ZERO_BIT_PADDING), - ("39001", SqlState::E_R_I_E_INVALID_SQLSTATE_RETURNED), + ("42P15", SqlState::INVALID_SCHEMA_DEFINITION), + ("55006", SqlState::OBJECT_IN_USE), + ("2203F", SqlState::SQL_JSON_SCALAR_REQUIRED), ("22014", SqlState::INVALID_ARGUMENT_FOR_NTILE), - ("2200N", SqlState::INVALID_XML_CONTENT), + ("03000", SqlState::SQL_STATEMENT_NOT_YET_COMPLETE), + ("22008", SqlState::DATETIME_FIELD_OVERFLOW), + ("08006", SqlState::CONNECTION_FAILURE), ("42P01", SqlState::UNDEFINED_TABLE), - ("42P03", SqlState::DUPLICATE_CURSOR), - ("25003", SqlState::INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION), + ("40P01", SqlState::T_R_DEADLOCK_DETECTED), + ("0L000", SqlState::INVALID_GRANTOR), + ("22005", SqlState::ERROR_IN_ASSIGNMENT), + ("42622", SqlState::NAME_TOO_LONG), + ("57P04", SqlState::DATABASE_DROPPED), + ("42803", SqlState::GROUPING_ERROR), + ("22P01", SqlState::FLOATING_POINT_EXCEPTION), + ("42P18", SqlState::INDETERMINATE_DATATYPE), + ("38004", SqlState::E_R_E_READING_SQL_DATA_NOT_PERMITTED), + ("39P03", SqlState::E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED), + ("2200N", SqlState::INVALID_XML_CONTENT), + ("57P02", SqlState::CRASH_SHUTDOWN), + ("23000", SqlState::INTEGRITY_CONSTRAINT_VIOLATION), + ("0F000", SqlState::LOCATOR_EXCEPTION), + ("08000", SqlState::CONNECTION_EXCEPTION), + ("2202E", SqlState::ARRAY_ELEMENT_ERROR), + ("22024", SqlState::UNTERMINATED_C_STRING), + ("08P01", SqlState::PROTOCOL_VIOLATION), + ("22023", SqlState::INVALID_PARAMETER_VALUE), + ("22031", SqlState::INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION), + ("HV00P", SqlState::FDW_NO_SCHEMAS), + ("23514", SqlState::CHECK_VIOLATION), + ("HV00Q", SqlState::FDW_SCHEMA_NOT_FOUND), + ("22P05", SqlState::UNTRANSLATABLE_CHARACTER), + ("53400", SqlState::CONFIGURATION_LIMIT_EXCEEDED), + ("3F000", SqlState::INVALID_SCHEMA_NAME), ("22037", SqlState::NON_UNIQUE_KEYS_IN_A_JSON_OBJECT), - ("22000", SqlState::DATA_EXCEPTION), - ("28P01", SqlState::INVALID_PASSWORD), - ("HV00A", SqlState::FDW_INVALID_STRING_FORMAT), - ("42P06", SqlState::DUPLICATE_SCHEMA), - ("HV00D", SqlState::FDW_INVALID_OPTION_NAME), - ("55P03", SqlState::LOCK_NOT_AVAILABLE), - ("HV021", SqlState::FDW_INCONSISTENT_DESCRIPTOR_INFORMATION), - ("42712", SqlState::DUPLICATE_ALIAS), - ("38000", SqlState::EXTERNAL_ROUTINE_EXCEPTION), - ("HV00N", SqlState::FDW_UNABLE_TO_ESTABLISH_CONNECTION), + ("22004", SqlState::NULL_VALUE_NOT_ALLOWED), ("2200B", SqlState::ESCAPE_CHARACTER_CONFLICT), - ("42P21", SqlState::COLLATION_MISMATCH), - ("42703", SqlState::UNDEFINED_COLUMN), - ("57P04", SqlState::DATABASE_DROPPED), - ("22P04", SqlState::BAD_COPY_FILE_FORMAT), - ("01006", SqlState::WARNING_PRIVILEGE_NOT_REVOKED), - ("HV007", SqlState::FDW_INVALID_COLUMN_NAME), + ("HV090", SqlState::FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH), + ("HV00R", SqlState::FDW_TABLE_NOT_FOUND), + ("42723", SqlState::DUPLICATE_FUNCTION), + ("22009", SqlState::INVALID_TIME_ZONE_DISPLACEMENT_VALUE), + ("HV00N", SqlState::FDW_UNABLE_TO_ESTABLISH_CONNECTION), + ("3B000", SqlState::SAVEPOINT_EXCEPTION), + ("22018", SqlState::INVALID_CHARACTER_VALUE_FOR_CAST), + ("HV004", SqlState::FDW_INVALID_DATA_TYPE), + ("08003", SqlState::CONNECTION_DOES_NOT_EXIST), + ("42P02", SqlState::UNDEFINED_PARAMETER), + ("23001", SqlState::RESTRICT_VIOLATION), ("HV00C", SqlState::FDW_INVALID_OPTION_INDEX), - ("25001", SqlState::ACTIVE_SQL_TRANSACTION), - ("42809", SqlState::WRONG_OBJECT_TYPE), - ("22P02", SqlState::INVALID_TEXT_REPRESENTATION), - ("42P20", SqlState::WINDOWING_ERROR), - ("24000", SqlState::INVALID_CURSOR_STATE), + ("HV010", SqlState::FDW_FUNCTION_SEQUENCE_ERROR), + ("28P01", SqlState::INVALID_PASSWORD), + ("55000", SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE), + ("2201X", SqlState::INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE), + ("P0001", SqlState::RAISE_EXCEPTION), + ("25000", SqlState::INVALID_TRANSACTION_STATE), + ("42704", SqlState::UNDEFINED_OBJECT), + ("22022", SqlState::INDICATOR_OVERFLOW), + ("09000", SqlState::TRIGGERED_ACTION_EXCEPTION), + ("22026", SqlState::STRING_DATA_LENGTH_MISMATCH), + ("01007", SqlState::WARNING_PRIVILEGE_NOT_GRANTED), + ("2200H", SqlState::SEQUENCE_GENERATOR_LIMIT_EXCEEDED), + ("25007", SqlState::SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED), + ("42701", SqlState::DUPLICATE_COLUMN), + ("42P08", SqlState::AMBIGUOUS_PARAMETER), + ("2201B", SqlState::INVALID_REGULAR_EXPRESSION), + ("22036", SqlState::NON_NUMERIC_SQL_JSON_ITEM), ("22011", SqlState::SUBSTRING_ERROR), - ("00000", SqlState::SUCCESSFUL_COMPLETION), - ("2202G", SqlState::INVALID_TABLESAMPLE_REPEAT), - ("P0000", SqlState::PLPGSQL_ERROR), - ("38003", SqlState::E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), - ("0100C", SqlState::WARNING_DYNAMIC_RESULT_SETS_RETURNED), - ("2200F", SqlState::ZERO_LENGTH_CHARACTER_STRING), - ("40P01", SqlState::T_R_DEADLOCK_DETECTED), + ("0LP01", SqlState::INVALID_GRANT_OPERATION), ]), }; From fbc42ecbe88eb1712a3c3650f295e9d84d09df5a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 26 Dec 2020 15:51:22 -0500 Subject: [PATCH 077/420] Stop setting timezone to UTC Closes #147 --- tokio-postgres/src/connect_raw.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/src/connect_raw.rs b/tokio-postgres/src/connect_raw.rs index d07d5a2df..3c6658481 100644 --- a/tokio-postgres/src/connect_raw.rs +++ b/tokio-postgres/src/connect_raw.rs @@ -111,7 +111,7 @@ where S: AsyncRead + AsyncWrite + Unpin, T: AsyncRead + AsyncWrite + Unpin, { - let mut params = vec![("client_encoding", "UTF8"), ("timezone", "UTC")]; + let mut params = vec![("client_encoding", "UTF8")]; if let Some(user) = &config.user { params.push(("user", &**user)); } From e2d327399b6ff423a1921fdb4f41b4a584386bac Mon Sep 17 00:00:00 2001 From: Bernardo Uriarte Blanco Date: Sat, 26 Dec 2020 23:17:04 +0100 Subject: [PATCH 078/420] add `client` method to `GenericClient` --- tokio-postgres/src/generic_client.rs | 11 +++++++++++ tokio-postgres/src/transaction.rs | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/tokio-postgres/src/generic_client.rs b/tokio-postgres/src/generic_client.rs index df2c6b842..911a587b6 100644 --- a/tokio-postgres/src/generic_client.rs +++ b/tokio-postgres/src/generic_client.rs @@ -12,6 +12,9 @@ mod private { /// This trait is "sealed", and cannot be implemented outside of this crate. #[async_trait] pub trait GenericClient: private::Sealed { + /// Get a reference to the underlying `Client` + fn client(&self) -> &Client; + /// Like `Client::execute`. async fn execute(&self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where @@ -74,6 +77,10 @@ impl private::Sealed for Client {} #[async_trait] impl GenericClient for Client { + fn client(&self) -> &Client { + self + } + async fn execute(&self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement + Sync + Send, @@ -152,6 +159,10 @@ impl private::Sealed for Transaction<'_> {} #[async_trait] #[allow(clippy::needless_lifetimes)] impl GenericClient for Transaction<'_> { + fn client(&self) -> &Client { + self.client() + } + async fn execute(&self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement + Sync + Send, diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index 45e9cc3aa..cf39d9186 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -64,6 +64,11 @@ impl<'a> Transaction<'a> { } } + /// Get a reference to the underlying `Client` + pub fn client(&self) -> &Client { + &self.client + } + /// Consumes the transaction, committing all changes made within it. pub async fn commit(mut self) -> Result<(), Error> { self.done = true; From e29439a5590157e3aedb373c33b96ccda6b3b959 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 30 Dec 2020 16:23:45 -0500 Subject: [PATCH 079/420] Delete FUNDING.yml --- .github/FUNDING.yml | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index b214efc24..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -github: [sfackler] From 7537e8a91819fa66d1590811e34a9c59b948b1af Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Fri, 8 Jan 2021 13:35:45 -0500 Subject: [PATCH 080/420] postgres-protocol: use RustCrypto md-5 crate Swap the md5 crate for the md-5 crate. Despite the latter's somewhat more suspicious name, it is part of the wider RustCrypto ecosystem, and shares code with the sha2 crate that postgres-protocol already uses. --- postgres-protocol/Cargo.toml | 2 +- postgres-protocol/src/authentication/mod.rs | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index 6746cfebd..1224c633d 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -14,7 +14,7 @@ byteorder = "1.0" bytes = "1.0" fallible-iterator = "0.2" hmac = "0.10" -md5 = "0.7" +md-5 = "0.9" memchr = "2.0" rand = "0.8" sha2 = "0.9" diff --git a/postgres-protocol/src/authentication/mod.rs b/postgres-protocol/src/authentication/mod.rs index edacb46e7..9cfd6034c 100644 --- a/postgres-protocol/src/authentication/mod.rs +++ b/postgres-protocol/src/authentication/mod.rs @@ -1,5 +1,5 @@ //! Authentication protocol support. -use md5::Context; +use md5::{Digest, Md5}; pub mod sasl; @@ -10,14 +10,13 @@ pub mod sasl; /// `PasswordMessage` message. #[inline] pub fn md5_hash(username: &[u8], password: &[u8], salt: [u8; 4]) -> String { - let mut context = Context::new(); - context.consume(password); - context.consume(username); - let output = context.compute(); - context = Context::new(); - context.consume(format!("{:x}", output)); - context.consume(&salt); - format!("md5{:x}", context.compute()) + let mut md5 = Md5::new(); + md5.update(password); + md5.update(username); + let output = md5.finalize_reset(); + md5.update(format!("{:x}", output)); + md5.update(&salt); + format!("md5{:x}", md5.finalize()) } #[cfg(test)] From f3cbc8ce0431efb1196727a7e6016a5928dcbd55 Mon Sep 17 00:00:00 2001 From: Jeff Davis Date: Mon, 14 Dec 2020 11:56:21 -0800 Subject: [PATCH 081/420] PgLsn type. --- postgres-protocol/src/lib.rs | 3 + postgres-protocol/src/types/mod.rs | 18 +++++- postgres-types/src/lib.rs | 4 ++ postgres-types/src/pg_lsn.rs | 79 ++++++++++++++++++++++++++ tokio-postgres/tests/test/types/mod.rs | 15 ++++- 5 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 postgres-types/src/pg_lsn.rs diff --git a/postgres-protocol/src/lib.rs b/postgres-protocol/src/lib.rs index b4374afa1..13de51e71 100644 --- a/postgres-protocol/src/lib.rs +++ b/postgres-protocol/src/lib.rs @@ -24,6 +24,9 @@ pub mod types; /// A Postgres OID. pub type Oid = u32; +/// A Postgres Log Sequence Number (LSN). +pub type Lsn = u64; + /// An enum indicating if a value is `NULL` or not. pub enum IsNull { /// The value is `NULL`. diff --git a/postgres-protocol/src/types/mod.rs b/postgres-protocol/src/types/mod.rs index 621c01cc2..436132c2c 100644 --- a/postgres-protocol/src/types/mod.rs +++ b/postgres-protocol/src/types/mod.rs @@ -8,7 +8,7 @@ use std::io::Read; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::str; -use crate::{write_nullable, FromUsize, IsNull, Oid}; +use crate::{write_nullable, FromUsize, IsNull, Lsn, Oid}; #[cfg(test)] mod test; @@ -142,6 +142,22 @@ pub fn int8_from_sql(mut buf: &[u8]) -> Result Result> { + let v = buf.read_u64::()?; + if !buf.is_empty() { + return Err("invalid buffer size".into()); + } + Ok(v) +} + /// Serializes a `FLOAT4` value. #[inline] pub fn float4_to_sql(v: f32, buf: &mut BytesMut) { diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 2909b81ef..e7cc781cd 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -130,6 +130,9 @@ use crate::type_gen::{Inner, Other}; #[doc(inline)] pub use postgres_protocol::Oid; +#[doc(inline)] +pub use pg_lsn::PgLsn; + pub use crate::special::{Date, Timestamp}; use bytes::BytesMut; @@ -204,6 +207,7 @@ mod uuid_08; #[cfg(feature = "with-time-0_2")] extern crate time_02 as time; +mod pg_lsn; #[doc(hidden)] pub mod private; mod special; diff --git a/postgres-types/src/pg_lsn.rs b/postgres-types/src/pg_lsn.rs new file mode 100644 index 000000000..f0bbf4022 --- /dev/null +++ b/postgres-types/src/pg_lsn.rs @@ -0,0 +1,79 @@ +//! Log Sequence Number (LSN) type for PostgreSQL Write-Ahead Log +//! (WAL), also known as the transaction log. + +use bytes::BytesMut; +use postgres_protocol::types; +use std::error::Error; +use std::fmt; +use std::str::FromStr; + +use crate::{FromSql, IsNull, ToSql, Type}; + +/// Postgres `PG_LSN` type. +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +pub struct PgLsn(u64); + +/// Error parsing LSN. +#[derive(Debug)] +pub struct ParseLsnError(()); + +impl From for PgLsn { + fn from(lsn_u64: u64) -> Self { + PgLsn(lsn_u64) + } +} + +impl From for u64 { + fn from(lsn: PgLsn) -> u64 { + lsn.0 + } +} + +impl FromStr for PgLsn { + type Err = ParseLsnError; + + fn from_str(lsn_str: &str) -> Result { + let split: Vec<&str> = lsn_str.split('/').collect(); + if split.len() == 2 { + let (hi, lo) = ( + u64::from_str_radix(split[0], 16).map_err(|_| ParseLsnError(()))?, + u64::from_str_radix(split[1], 16).map_err(|_| ParseLsnError(()))?, + ); + Ok(PgLsn((hi << 32) | lo)) + } else { + Err(ParseLsnError(())) + } + } +} + +impl fmt::Display for PgLsn { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:X}/{:X}", self.0 >> 32, self.0 & 0x00000000ffffffff) + } +} + +impl fmt::Debug for PgLsn { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_fmt(format_args!("{}", self)) + } +} + +impl<'a> FromSql<'a> for PgLsn { + fn from_sql(_: &Type, raw: &'a [u8]) -> Result> { + let v = types::lsn_from_sql(raw)?; + Ok(v.into()) + } + + accepts!(PG_LSN); +} + +impl ToSql for PgLsn { + fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result> { + types::lsn_to_sql((*self).into(), out); + Ok(IsNull::No) + } + + accepts!(PG_LSN); + + to_sql_checked!(); +} diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index 168ca3a4d..c1480bf84 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -6,8 +6,9 @@ use std::f64; use std::fmt; use std::net::IpAddr; use std::result; +use std::str::FromStr; use std::time::{Duration, UNIX_EPOCH}; -use tokio_postgres::types::{FromSql, FromSqlOwned, IsNull, Kind, ToSql, Type, WrongType}; +use tokio_postgres::types::{FromSql, FromSqlOwned, IsNull, Kind, PgLsn, ToSql, Type, WrongType}; use crate::connect; use bytes::BytesMut; @@ -135,6 +136,18 @@ async fn test_i64_params() { .await; } +#[tokio::test] +async fn test_lsn_params() { + test_type( + "PG_LSN", + &[ + (Some(PgLsn::from_str("2B/1757980").unwrap()), "'2B/1757980'"), + (None, "NULL"), + ], + ) + .await +} + #[tokio::test] async fn test_f32_params() { test_type( From e4e48a06b79efab2ecfba6d40b2dbc1d9eeffb36 Mon Sep 17 00:00:00 2001 From: Jeff Davis Date: Thu, 7 Jan 2021 18:25:53 -0800 Subject: [PATCH 082/420] Add password module for hashing on the client side. Hashing a password on the client side is useful so that you can set a user's password without ever sending it in plain text to the server. This avoids leaking passwords in the log or elsewhere. --- postgres-protocol/src/authentication/sasl.rs | 2 +- postgres-protocol/src/lib.rs | 1 + postgres-protocol/src/password/mod.rs | 104 +++++++++++++++++++ postgres-protocol/src/password/test.rs | 19 ++++ 4 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 postgres-protocol/src/password/mod.rs create mode 100644 postgres-protocol/src/password/test.rs diff --git a/postgres-protocol/src/authentication/sasl.rs b/postgres-protocol/src/authentication/sasl.rs index d95471133..7c0d1754f 100644 --- a/postgres-protocol/src/authentication/sasl.rs +++ b/postgres-protocol/src/authentication/sasl.rs @@ -32,7 +32,7 @@ fn normalize(pass: &[u8]) -> Vec { } } -fn hi(str: &[u8], salt: &[u8], i: u32) -> [u8; 32] { +pub(crate) fn hi(str: &[u8], salt: &[u8], i: u32) -> [u8; 32] { let mut hmac = Hmac::::new_varkey(str).expect("HMAC is able to accept all key sizes"); hmac.update(salt); hmac.update(&[0, 0, 0, 1]); diff --git a/postgres-protocol/src/lib.rs b/postgres-protocol/src/lib.rs index 13de51e71..c9fe0ee19 100644 --- a/postgres-protocol/src/lib.rs +++ b/postgres-protocol/src/lib.rs @@ -19,6 +19,7 @@ use std::io; pub mod authentication; pub mod escape; pub mod message; +pub mod password; pub mod types; /// A Postgres OID. diff --git a/postgres-protocol/src/password/mod.rs b/postgres-protocol/src/password/mod.rs new file mode 100644 index 000000000..ccb95c79b --- /dev/null +++ b/postgres-protocol/src/password/mod.rs @@ -0,0 +1,104 @@ +//! Functions to encrypt a password in the client. +//! +//! This is intended to be used by client applications that wish to +//! send commands like `ALTER USER joe PASSWORD 'pwd'`. The password +//! need not be sent in cleartext if it is encrypted on the client +//! side. This is good because it ensures the cleartext password won't +//! end up in logs pg_stat displays, etc. + +use crate::authentication::sasl; +use hmac::{Hmac, Mac, NewMac}; +use md5::Md5; +use rand::RngCore; +use sha2::digest::FixedOutput; +use sha2::{Digest, Sha256}; + +#[cfg(test)] +mod test; + +const SCRAM_DEFAULT_ITERATIONS: u32 = 4096; +const SCRAM_DEFAULT_SALT_LEN: usize = 16; + +/// Hash password using SCRAM-SHA-256 with a randomly-generated +/// salt. +/// +/// The client may assume the returned string doesn't contain any +/// 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(); + rng.fill_bytes(&mut salt); + scram_sha_256_salt(password, salt) +} + +// Internal implementation of scram_sha_256 with a caller-provided +// salt. This is useful for testing. +pub(crate) fn scram_sha_256_salt(password: &[u8], salt: [u8; SCRAM_DEFAULT_SALT_LEN]) -> String { + // Prepare the password, per [RFC + // 4013](https://tools.ietf.org/html/rfc4013), if possible. + // + // Postgres treats passwords as byte strings (without embedded NUL + // bytes), but SASL expects passwords to be valid UTF-8. + // + // Follow the behavior of libpq's PQencryptPasswordConn(), and + // also the backend. If the password is not valid UTF-8, or if it + // contains prohibited characters (such as non-ASCII whitespace), + // just skip the SASLprep step and use the original byte + // sequence. + let prepared: Vec = match std::str::from_utf8(password) { + Ok(password_str) => { + match stringprep::saslprep(password_str) { + Ok(p) => p.into_owned().into_bytes(), + // contains invalid characters; skip saslprep + Err(_) => Vec::from(password), + } + } + // not valid UTF-8; skip saslprep + Err(_) => Vec::from(password), + }; + + // salt password + let salted_password = sasl::hi(&prepared, &salt, SCRAM_DEFAULT_ITERATIONS); + + // client key + let mut hmac = + Hmac::::new_varkey(&salted_password).expect("HMAC is able to accept all key sizes"); + hmac.update(b"Client Key"); + let client_key = hmac.finalize().into_bytes(); + + // stored key + let mut hash = Sha256::default(); + hash.update(client_key.as_slice()); + let stored_key = hash.finalize_fixed(); + + // server key + let mut hmac = + Hmac::::new_varkey(&salted_password).expect("HMAC is able to accept all key sizes"); + hmac.update(b"Server Key"); + let server_key = hmac.finalize().into_bytes(); + + format!( + "SCRAM-SHA-256${}:{}${}:{}", + SCRAM_DEFAULT_ITERATIONS, + base64::encode(salt), + base64::encode(stored_key), + base64::encode(server_key) + ) +} + +/// **Not recommended, as MD5 is not considered to be secure.** +/// +/// Hash password using MD5 with the username as the salt. +/// +/// The client may assume the returned string doesn't contain any +/// special characters that would require escaping. +pub fn md5(password: &[u8], username: &str) -> String { + // salt password with username + let mut salted_password = Vec::from(password); + salted_password.extend_from_slice(username.as_bytes()); + + let mut hash = Md5::new(); + hash.update(&salted_password); + let digest = hash.finalize(); + format!("md5{:x}", digest) +} diff --git a/postgres-protocol/src/password/test.rs b/postgres-protocol/src/password/test.rs new file mode 100644 index 000000000..1432cb204 --- /dev/null +++ b/postgres-protocol/src/password/test.rs @@ -0,0 +1,19 @@ +use crate::password; + +#[test] +fn test_encrypt_scram_sha_256() { + // Specify the salt to make the test deterministic. Any bytes will do. + let salt: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + assert_eq!( + password::scram_sha_256_salt(b"secret", salt), + "SCRAM-SHA-256$4096:AQIDBAUGBwgJCgsMDQ4PEA==$8rrDg00OqaiWXJ7p+sCgHEIaBSHY89ZJl3mfIsf32oY=:05L1f+yZbiN8O0AnO40Og85NNRhvzTS57naKRWCcsIA=" + ); +} + +#[test] +fn test_encrypt_md5() { + assert_eq!( + password::md5(b"secret", "foo"), + "md54ab2c5d00339c4b2a4e921d2dc4edec7" + ); +} From 41375ebd3c676076920a2d644f292618d7ef8dcc Mon Sep 17 00:00:00 2001 From: Lachezar Lechev <8925621+elpiel@users.noreply.github.com> Date: Wed, 13 Jan 2021 11:53:29 +0200 Subject: [PATCH 083/420] Update tokio version in feature docs --- tokio-postgres/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 6e73b883d..e477687ac 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -103,7 +103,7 @@ //! //! | Feature | Description | Extra dependencies | Default | //! | ------- | ----------- | ------------------ | ------- | -//! | `runtime` | Enable convenience API for the connection process based on the `tokio` crate. | [tokio](https://crates.io/crates/tokio) 0.3 with the features `net` and `time` | yes | +//! | `runtime` | Enable convenience API for the connection process based on the `tokio` crate. | [tokio](https://crates.io/crates/tokio) 1.0 with the features `net` and `time` | yes | //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | //! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | From cc6a0ada01bcda2ed16995939d9305ea6dc26a3a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 16 Jan 2021 14:19:14 -0500 Subject: [PATCH 084/420] Add back Error::as_db_error Closes #732 --- tokio-postgres/src/error/mod.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tokio-postgres/src/error/mod.rs b/tokio-postgres/src/error/mod.rs index 3df529049..ee29a1dbb 100644 --- a/tokio-postgres/src/error/mod.rs +++ b/tokio-postgres/src/error/mod.rs @@ -414,14 +414,18 @@ impl Error { self.0.cause } + /// Returns the source of this error if it was a `DbError`. + /// + /// This is a simple convenience method. + pub fn as_db_error(&self) -> Option<&DbError> { + self.source().and_then(|e| e.downcast_ref::()) + } + /// Returns the SQLSTATE error code associated with the error. /// - /// This is a convenience method that downcasts the cause to a `DbError` - /// and returns its code. + /// This is a convenience method that downcasts the cause to a `DbError` and returns its code. pub fn code(&self) -> Option<&SqlState> { - self.source() - .and_then(|e| e.downcast_ref::()) - .map(DbError::code) + self.as_db_error().map(DbError::code) } fn new(kind: Kind, cause: Option>) -> Error { From 37fb39202a5892a39596b20fb4d0521ecf6aec70 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Wed, 13 Jan 2021 21:34:45 -0600 Subject: [PATCH 085/420] Added support for `geo-types` 0.7 via `with-geo-types-0_7` feature --- postgres-types/CHANGELOG.md | 6 ++ postgres-types/Cargo.toml | 4 +- .../src/{geo_types_06.rs => geo_types_07.rs} | 2 +- postgres-types/src/lib.rs | 4 +- postgres/CHANGELOG.md | 6 ++ postgres/Cargo.toml | 2 +- postgres/src/lib.rs | 3 +- tokio-postgres/CHANGELOG.md | 6 ++ tokio-postgres/Cargo.toml | 4 +- tokio-postgres/src/lib.rs | 3 +- .../tests/test/types/geo_types_04.rs | 60 ------------------- .../{geo_types_06.rs => geo_types_07.rs} | 3 +- tokio-postgres/tests/test/types/mod.rs | 6 +- 13 files changed, 32 insertions(+), 77 deletions(-) rename postgres-types/src/{geo_types_06.rs => geo_types_07.rs} (97%) delete mode 100644 tokio-postgres/tests/test/types/geo_types_04.rs rename tokio-postgres/tests/test/types/{geo_types_06.rs => geo_types_07.rs} (92%) diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index 4fb55631b..9f9da7989 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## Unreleased + +### Added + +* Added support for `geo-types` 0.7 via `with-geo-types-0_7` feature. + ## v0.2.0 - 2020-12-25 ### Changed diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 40edc621b..ce5b0ab06 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -15,7 +15,7 @@ derive = ["postgres-derive"] with-bit-vec-0_6 = ["bit-vec-06"] with-chrono-0_4 = ["chrono-04"] with-eui48-0_4 = ["eui48-04"] -with-geo-types-0_6 = ["geo-types-06"] +with-geo-types-0_7 = ["geo-types-0_7"] with-serde_json-1 = ["serde-1", "serde_json-1"] with-uuid-0_8 = ["uuid-08"] with-time-0_2 = ["time-02"] @@ -29,7 +29,7 @@ postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-deri bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } chrono-04 = { version = "0.4.16", package = "chrono", default-features = false, features = ["clock"], optional = true } eui48-04 = { version = "0.4", package = "eui48", optional = true } -geo-types-06 = { version = "0.6", package = "geo-types", optional = true } +geo-types-0_7 = { version = "0.7", package = "geo-types", optional = true } serde-1 = { version = "1.0", package = "serde", optional = true } serde_json-1 = { version = "1.0", package = "serde_json", optional = true } uuid-08 = { version = "0.8", package = "uuid", optional = true } diff --git a/postgres-types/src/geo_types_06.rs b/postgres-types/src/geo_types_07.rs similarity index 97% rename from postgres-types/src/geo_types_06.rs rename to postgres-types/src/geo_types_07.rs index 0f0b14fd9..7dfb51056 100644 --- a/postgres-types/src/geo_types_06.rs +++ b/postgres-types/src/geo_types_07.rs @@ -1,6 +1,6 @@ use bytes::BytesMut; use fallible_iterator::FallibleIterator; -use geo_types_06::{Coordinate, LineString, Point, Rect}; +use geo_types_0_7::{Coordinate, LineString, Point, Rect}; use postgres_protocol::types; use std::error::Error; diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index e7cc781cd..d4595091a 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -194,8 +194,8 @@ mod bit_vec_06; mod chrono_04; #[cfg(feature = "with-eui48-0_4")] mod eui48_04; -#[cfg(feature = "with-geo-types-0_6")] -mod geo_types_06; +#[cfg(feature = "with-geo-types-0_7")] +mod geo_types_07; #[cfg(feature = "with-serde_json-1")] mod serde_json_1; #[cfg(feature = "with-time-0_2")] diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index 2376068a8..66e66c6fb 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## Unreleased + +### Added + +* Added support for `geo-types` 0.7 via `with-geo-types-0_7` feature. + ## v0.19.0 - 2020-12-25 ### Changed diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index ed63d0c1a..7916a5e0d 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -24,7 +24,7 @@ circle-ci = { repository = "sfackler/rust-postgres" } with-bit-vec-0_6 = ["tokio-postgres/with-bit-vec-0_6"] with-chrono-0_4 = ["tokio-postgres/with-chrono-0_4"] with-eui48-0_4 = ["tokio-postgres/with-eui48-0_4"] -with-geo-types-0_6 = ["tokio-postgres/with-geo-types-0_6"] +with-geo-types-0_7 = ["tokio-postgres/with-geo-types-0_7"] with-serde_json-1 = ["tokio-postgres/with-serde_json-1"] with-uuid-0_8 = ["tokio-postgres/with-uuid-0_8"] with-time-0_2 = ["tokio-postgres/with-time-0_2"] diff --git a/postgres/src/lib.rs b/postgres/src/lib.rs index f25fe1175..fe0c1f6c3 100644 --- a/postgres/src/lib.rs +++ b/postgres/src/lib.rs @@ -56,8 +56,7 @@ //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | //! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | -//! | `with-geo-types-0_4` | Enable support for the 0.4 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.4.0) 0.4 | no | -//! | `with-geo-types-0_5` | Enable support for the 0.5 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.5.0) 0.5 | no | +//! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | //! | `with-time-0_2` | Enable support for the `time` crate. | [time](https://crates.io/crates/time) 0.2 | no | diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 7d513daa2..db984ca18 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## Unreleased + +### Added + +* Added support for `geo-types` 0.7 via `with-geo-types-0_7` feature. + ## v0.7.0 - 2020-12-25 ### Changed diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 613af127f..47e371675 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -30,7 +30,7 @@ runtime = ["tokio/net", "tokio/time"] with-bit-vec-0_6 = ["postgres-types/with-bit-vec-0_6"] with-chrono-0_4 = ["postgres-types/with-chrono-0_4"] with-eui48-0_4 = ["postgres-types/with-eui48-0_4"] -with-geo-types-0_6 = ["postgres-types/with-geo-types-0_6"] +with-geo-types-0_7 = ["postgres-types/with-geo-types-0_7"] with-serde_json-1 = ["postgres-types/with-serde_json-1"] with-uuid-0_8 = ["postgres-types/with-uuid-0_8"] with-time-0_2 = ["postgres-types/with-time-0_2"] @@ -60,7 +60,7 @@ criterion = "0.3" bit-vec-06 = { version = "0.6", package = "bit-vec" } chrono-04 = { version = "0.4", package = "chrono", default-features = false } eui48-04 = { version = "0.4", package = "eui48" } -geo-types-06 = { version = "0.6", package = "geo-types" } +geo-types-07 = { version = "0.7", package = "geo-types" } serde-1 = { version = "1.0", package = "serde" } serde_json-1 = { version = "1.0", package = "serde_json" } uuid-08 = { version = "0.8", package = "uuid" } diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index e477687ac..d62b8631d 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -107,8 +107,7 @@ //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | //! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | -//! | `with-geo-types-0_4` | Enable support for the 0.4 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.4.0) 0.4 | no | -//! | `with-geo-types-0_5` | Enable support for the 0.5 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.5.0) 0.5 | no | +//! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | //! | `with-time-0_2` | Enable support for the `time` crate. | [time](https://crates.io/crates/time) 0.2 | no | diff --git a/tokio-postgres/tests/test/types/geo_types_04.rs b/tokio-postgres/tests/test/types/geo_types_04.rs deleted file mode 100644 index a4f0ac6f6..000000000 --- a/tokio-postgres/tests/test/types/geo_types_04.rs +++ /dev/null @@ -1,60 +0,0 @@ -use geo_types_04::{Coordinate, LineString, Point, Rect}; - -use crate::types::test_type; - -#[tokio::test] -async fn test_point_params() { - test_type( - "POINT", - &[ - (Some(Point::new(0.0, 0.0)), "POINT(0, 0)"), - (Some(Point::new(-3.2, 1.618)), "POINT(-3.2, 1.618)"), - (None, "NULL"), - ], - ) - .await; -} - -#[tokio::test] -async fn test_box_params() { - test_type( - "BOX", - &[ - ( - Some(Rect { - min: Coordinate { x: -3.2, y: 1.618 }, - max: Coordinate { - x: 160.0, - y: 69701.5615, - }, - }), - "BOX(POINT(160.0, 69701.5615), POINT(-3.2, 1.618))", - ), - (None, "NULL"), - ], - ) - .await; -} - -#[tokio::test] -async fn test_path_params() { - let points = vec![ - Coordinate { x: 0., y: 0. }, - Coordinate { x: -3.2, y: 1.618 }, - Coordinate { - x: 160.0, - y: 69701.5615, - }, - ]; - test_type( - "PATH", - &[ - ( - Some(LineString(points)), - "path '((0, 0), (-3.2, 1.618), (160.0, 69701.5615))'", - ), - (None, "NULL"), - ], - ) - .await; -} diff --git a/tokio-postgres/tests/test/types/geo_types_06.rs b/tokio-postgres/tests/test/types/geo_types_07.rs similarity index 92% rename from tokio-postgres/tests/test/types/geo_types_06.rs rename to tokio-postgres/tests/test/types/geo_types_07.rs index 7195abc06..85ff2553a 100644 --- a/tokio-postgres/tests/test/types/geo_types_06.rs +++ b/tokio-postgres/tests/test/types/geo_types_07.rs @@ -1,4 +1,5 @@ -use geo_types_06::{Coordinate, LineString, Point, Rect}; +#[cfg(feature = "with-geo-types-0_7")] +use geo_types_07::{Coordinate, LineString, Point, Rect}; use crate::types::test_type; diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index c1480bf84..abf058297 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -19,10 +19,8 @@ mod bit_vec_06; mod chrono_04; #[cfg(feature = "with-eui48-0_4")] mod eui48_04; -#[cfg(feature = "with-geo-types-0_4")] -mod geo_types_04; -#[cfg(feature = "with-geo-types-0_6")] -mod geo_types_06; +#[cfg(feature = "with-geo-types-0_7")] +mod geo_types_07; #[cfg(feature = "with-serde_json-1")] mod serde_json_1; #[cfg(feature = "with-time-0_2")] From 8b8491f31dc55e5cdc286c616a9900af622f9fa7 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Mon, 25 Jan 2021 14:49:06 -0600 Subject: [PATCH 086/420] retain support for geo-types-0.6 --- postgres-types/Cargo.toml | 2 + postgres-types/src/geo_types_06.rs | 72 +++++++++++++++++++ postgres-types/src/lib.rs | 2 + postgres/Cargo.toml | 1 + postgres/src/lib.rs | 1 + tokio-postgres/Cargo.toml | 2 + tokio-postgres/src/lib.rs | 1 + .../tests/test/types/geo_types_06.rs | 60 ++++++++++++++++ tokio-postgres/tests/test/types/mod.rs | 2 + 9 files changed, 143 insertions(+) create mode 100644 postgres-types/src/geo_types_06.rs create mode 100644 tokio-postgres/tests/test/types/geo_types_06.rs diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index ce5b0ab06..7d48596ae 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -15,6 +15,7 @@ derive = ["postgres-derive"] with-bit-vec-0_6 = ["bit-vec-06"] with-chrono-0_4 = ["chrono-04"] with-eui48-0_4 = ["eui48-04"] +with-geo-types-0_6 = ["geo-types-06"] with-geo-types-0_7 = ["geo-types-0_7"] with-serde_json-1 = ["serde-1", "serde_json-1"] with-uuid-0_8 = ["uuid-08"] @@ -29,6 +30,7 @@ postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-deri bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } chrono-04 = { version = "0.4.16", package = "chrono", default-features = false, features = ["clock"], optional = true } eui48-04 = { version = "0.4", package = "eui48", optional = true } +geo-types-06 = { version = "0.6", package = "geo-types", optional = true } geo-types-0_7 = { version = "0.7", package = "geo-types", optional = true } serde-1 = { version = "1.0", package = "serde", optional = true } serde_json-1 = { version = "1.0", package = "serde_json", optional = true } diff --git a/postgres-types/src/geo_types_06.rs b/postgres-types/src/geo_types_06.rs new file mode 100644 index 000000000..0f0b14fd9 --- /dev/null +++ b/postgres-types/src/geo_types_06.rs @@ -0,0 +1,72 @@ +use bytes::BytesMut; +use fallible_iterator::FallibleIterator; +use geo_types_06::{Coordinate, LineString, Point, Rect}; +use postgres_protocol::types; +use std::error::Error; + +use crate::{FromSql, IsNull, ToSql, Type}; + +impl<'a> FromSql<'a> for Point { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let point = types::point_from_sql(raw)?; + Ok(Point::new(point.x(), point.y())) + } + + accepts!(POINT); +} + +impl ToSql for Point { + fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result> { + types::point_to_sql(self.x(), self.y(), out); + Ok(IsNull::No) + } + + accepts!(POINT); + to_sql_checked!(); +} + +impl<'a> FromSql<'a> for Rect { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let rect = types::box_from_sql(raw)?; + Ok(Rect::new( + (rect.lower_left().x(), rect.lower_left().y()), + (rect.upper_right().x(), rect.upper_right().y()), + )) + } + + accepts!(BOX); +} + +impl ToSql for Rect { + fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result> { + types::box_to_sql(self.min().x, self.min().y, self.max().x, self.max().y, out); + Ok(IsNull::No) + } + + accepts!(BOX); + to_sql_checked!(); +} + +impl<'a> FromSql<'a> for LineString { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let path = types::path_from_sql(raw)?; + let points = path + .points() + .map(|p| Ok(Coordinate { x: p.x(), y: p.y() })) + .collect()?; + Ok(LineString(points)) + } + + accepts!(PATH); +} + +impl ToSql for LineString { + fn to_sql(&self, _: &Type, out: &mut BytesMut) -> Result> { + let closed = false; // always encode an open path from LineString + types::path_to_sql(closed, self.0.iter().map(|p| (p.x, p.y)), out)?; + Ok(IsNull::No) + } + + accepts!(PATH); + to_sql_checked!(); +} diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index d4595091a..e9a7c10a2 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -194,6 +194,8 @@ mod bit_vec_06; mod chrono_04; #[cfg(feature = "with-eui48-0_4")] mod eui48_04; +#[cfg(feature = "with-geo-types-0_6")] +mod geo_types_06; #[cfg(feature = "with-geo-types-0_7")] mod geo_types_07; #[cfg(feature = "with-serde_json-1")] diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 7916a5e0d..0128f8a4e 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -24,6 +24,7 @@ circle-ci = { repository = "sfackler/rust-postgres" } with-bit-vec-0_6 = ["tokio-postgres/with-bit-vec-0_6"] with-chrono-0_4 = ["tokio-postgres/with-chrono-0_4"] with-eui48-0_4 = ["tokio-postgres/with-eui48-0_4"] +with-geo-types-0_6 = ["tokio-postgres/with-geo-types-0_6"] with-geo-types-0_7 = ["tokio-postgres/with-geo-types-0_7"] with-serde_json-1 = ["tokio-postgres/with-serde_json-1"] with-uuid-0_8 = ["tokio-postgres/with-uuid-0_8"] diff --git a/postgres/src/lib.rs b/postgres/src/lib.rs index fe0c1f6c3..4513aeef7 100644 --- a/postgres/src/lib.rs +++ b/postgres/src/lib.rs @@ -56,6 +56,7 @@ //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | //! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | +//! | `with-geo-types-0_6` | Enable support for the 0.6 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.6.0) 0.6 | no | //! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 47e371675..254ebe62e 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -30,6 +30,7 @@ runtime = ["tokio/net", "tokio/time"] with-bit-vec-0_6 = ["postgres-types/with-bit-vec-0_6"] with-chrono-0_4 = ["postgres-types/with-chrono-0_4"] with-eui48-0_4 = ["postgres-types/with-eui48-0_4"] +with-geo-types-0_6 = ["postgres-types/with-geo-types-0_6"] with-geo-types-0_7 = ["postgres-types/with-geo-types-0_7"] with-serde_json-1 = ["postgres-types/with-serde_json-1"] with-uuid-0_8 = ["postgres-types/with-uuid-0_8"] @@ -60,6 +61,7 @@ criterion = "0.3" bit-vec-06 = { version = "0.6", package = "bit-vec" } chrono-04 = { version = "0.4", package = "chrono", default-features = false } eui48-04 = { version = "0.4", package = "eui48" } +geo-types-06 = { version = "0.6", package = "geo-types" } geo-types-07 = { version = "0.7", package = "geo-types" } serde-1 = { version = "1.0", package = "serde" } serde_json-1 = { version = "1.0", package = "serde_json" } diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index d62b8631d..77713bb11 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -107,6 +107,7 @@ //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | //! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | +//! | `with-geo-types-0_6` | Enable support for the 0.6 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.6.0) 0.6 | no | //! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | diff --git a/tokio-postgres/tests/test/types/geo_types_06.rs b/tokio-postgres/tests/test/types/geo_types_06.rs new file mode 100644 index 000000000..7195abc06 --- /dev/null +++ b/tokio-postgres/tests/test/types/geo_types_06.rs @@ -0,0 +1,60 @@ +use geo_types_06::{Coordinate, LineString, Point, Rect}; + +use crate::types::test_type; + +#[tokio::test] +async fn test_point_params() { + test_type( + "POINT", + &[ + (Some(Point::new(0.0, 0.0)), "POINT(0, 0)"), + (Some(Point::new(-3.2, 1.618)), "POINT(-3.2, 1.618)"), + (None, "NULL"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_box_params() { + test_type( + "BOX", + &[ + ( + Some(Rect::new( + Coordinate { x: -3.2, y: 1.618 }, + Coordinate { + x: 160.0, + y: 69701.5615, + }, + )), + "BOX(POINT(160.0, 69701.5615), POINT(-3.2, 1.618))", + ), + (None, "NULL"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_path_params() { + let points = vec![ + Coordinate { x: 0., y: 0. }, + Coordinate { x: -3.2, y: 1.618 }, + Coordinate { + x: 160.0, + y: 69701.5615, + }, + ]; + test_type( + "PATH", + &[ + ( + Some(LineString(points)), + "path '((0, 0), (-3.2, 1.618), (160.0, 69701.5615))'", + ), + (None, "NULL"), + ], + ) + .await; +} diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index abf058297..11d128764 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -19,6 +19,8 @@ mod bit_vec_06; mod chrono_04; #[cfg(feature = "with-eui48-0_4")] mod eui48_04; +#[cfg(feature = "with-geo-types-0_6")] +mod geo_types_06; #[cfg(feature = "with-geo-types-0_7")] mod geo_types_07; #[cfg(feature = "with-serde_json-1")] From 77cfee0da1fff2d90c61e3033b962057ccd2ba3b Mon Sep 17 00:00:00 2001 From: George London Date: Fri, 5 Feb 2021 19:49:36 -0800 Subject: [PATCH 087/420] Fix minor docstring typo --- postgres/src/client.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres/src/client.rs b/postgres/src/client.rs index c052836f0..0ff2376e1 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -407,8 +407,8 @@ impl Client { /// /// # Warning /// - /// Prepared statements should be use for any query which contains user-specified data, as they provided the - /// functionality to safely imbed that data in the request. Do not form statements via string concatenation and pass + /// Prepared statements should be used for any query which contains user-specified data, as they provided the + /// functionality to safely embed that data in the request. Do not form statements via string concatenation and pass /// them to this method! pub fn simple_query(&mut self, query: &str) -> Result, Error> { self.connection.block_on(self.client.simple_query(query)) From 85a6c95a695d645933a7569206ba823dd78fc725 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 16 Mar 2021 20:24:16 -0400 Subject: [PATCH 088/420] switch CI to github actions --- .circleci/config.yml | 42 -------------------- .github/workflows/ci.yml | 83 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 42 deletions(-) delete mode 100644 .circleci/config.yml create mode 100644 .github/workflows/ci.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 8038a2c0f..000000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,42 +0,0 @@ -restore_registry: &RESTORE_REGISTRY - restore_cache: - key: registry -save_registry: &SAVE_REGISTRY - save_cache: - key: registry-{{ .BuildNum }} - paths: - - /usr/local/cargo/registry/index -deps_key: &DEPS_KEY - key: deps-{{ checksum "~/rust-version" }}-{{ checksum "Cargo.lock" }} -restore_deps: &RESTORE_DEPS - restore_cache: - <<: *DEPS_KEY -save_deps: &SAVE_DEPS - save_cache: - <<: *DEPS_KEY - paths: - - target - - /usr/local/cargo/registry/cache - -version: 2 -jobs: - build: - docker: - - image: rust:1.45.0 - environment: - RUSTFLAGS: -D warnings - - image: sfackler/rust-postgres-test:6 - steps: - - checkout - - run: rustup component add rustfmt clippy - - *RESTORE_REGISTRY - - run: cargo generate-lockfile - - *SAVE_REGISTRY - - run: rustc --version > ~/rust-version - - *RESTORE_DEPS - - run: cargo fmt --all -- --check - - run: cargo clippy --all --all-targets --all-features - - run: cargo test --all - - run: cargo test --manifest-path tokio-postgres/Cargo.toml --no-default-features - - run: cargo test --manifest-path tokio-postgres/Cargo.toml --all-features - - *SAVE_DEPS diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..7191eb9e4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,83 @@ +name: CI + +on: + pull_request: + branches: + - master + push: + branches: + - master + +env: + RUSTFLAGS: -Dwarnings + RUST_BACKTRACE: 1 + +jobs: + rustfmt: + name: rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: sfackler/actions/rustup@master + - uses: sfackler/actions/rustfmt@master + + clippy: + name: clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: sfackler/actions/rustup@master + - run: echo "::set-output name=version::$(rustc --version)" + id: rust-version + - uses: actions/cache@v1 + with: + path: ~/.cargo/registry/index + key: index-${{ runner.os }}-${{ github.run_number }} + restore-keys: | + index-${{ runner.os }}- + - run: cargo generate-lockfile + - uses: actions/cache@v1 + with: + path: ~/.cargo/registry/cache + key: registry-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} + - run: cargo fetch + - uses: actions/cache@v1 + with: + path: target + key: clippy-target-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}y + - run: cargo clippy --all --all-targets + + test: + name: test + runs-on: ubuntu-latest + services: + postgres: + image: sfackler/rust-postgres-test:6 + ports: + - 5433:5433 + steps: + - uses: actions/checkout@v2 + - uses: sfackler/actions/rustup@master + with: + version: 1.45.0 + - run: echo "::set-output name=version::$(rustc --version)" + id: rust-version + - uses: actions/cache@v1 + with: + path: ~/.cargo/registry/index + key: index-${{ runner.os }}-${{ github.run_number }} + restore-keys: | + index-${{ runner.os }}- + - run: cargo generate-lockfile + - uses: actions/cache@v1 + with: + path: ~/.cargo/registry/cache + key: registry-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} + - run: cargo fetch + - uses: actions/cache@v1 + with: + path: target + key: test-target-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}y + - run: cargo test --all + - run: cargo test --manifest-path tokio-postgres/Cargo.toml --no-default-features + - run: cargo test --manifest-path tokio-postgres/Cargo.toml --all-features From ad2c8cf592899aed0e5d141af4411897d310e559 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 16 Mar 2021 20:32:26 -0400 Subject: [PATCH 089/420] clippy --- postgres-protocol/src/types/mod.rs | 16 +++++++--------- tokio-postgres/src/config.rs | 8 ++++---- tokio-postgres/src/connection.rs | 3 ++- tokio-postgres/tests/test/types/mod.rs | 6 +----- 4 files changed, 14 insertions(+), 19 deletions(-) diff --git a/postgres-protocol/src/types/mod.rs b/postgres-protocol/src/types/mod.rs index 436132c2c..a595f5a30 100644 --- a/postgres-protocol/src/types/mod.rs +++ b/postgres-protocol/src/types/mod.rs @@ -231,9 +231,9 @@ fn write_pascal_string(s: &str, buf: &mut BytesMut) -> Result<(), StdBox( - mut buf: &'a [u8], -) -> Result, StdBox> { +pub fn hstore_from_sql( + mut buf: &[u8], +) -> Result, StdBox> { let count = buf.read_i32::()?; if count < 0 { return Err("invalid entry count".into()); @@ -319,9 +319,7 @@ where /// Deserializes a `VARBIT` or `BIT` value. #[inline] -pub fn varbit_from_sql<'a>( - mut buf: &'a [u8], -) -> Result, StdBox> { +pub fn varbit_from_sql(mut buf: &[u8]) -> Result, StdBox> { let len = buf.read_i32::()?; if len < 0 { return Err("invalid varbit length: varbit < 0".into()); @@ -508,7 +506,7 @@ where /// Deserializes an array value. #[inline] -pub fn array_from_sql<'a>(mut buf: &'a [u8]) -> Result, StdBox> { +pub fn array_from_sql(mut buf: &[u8]) -> Result, StdBox> { let dimensions = buf.read_i32::()?; if dimensions < 0 { return Err("invalid dimension count".into()); @@ -738,7 +736,7 @@ pub enum RangeBound { /// Deserializes a range value. #[inline] -pub fn range_from_sql<'a>(mut buf: &'a [u8]) -> Result, StdBox> { +pub fn range_from_sql(mut buf: &[u8]) -> Result, StdBox> { let tag = buf.read_u8()?; if tag == RANGE_EMPTY { @@ -911,7 +909,7 @@ where /// Deserializes a Postgres path. #[inline] -pub fn path_from_sql<'a>(mut buf: &'a [u8]) -> Result, StdBox> { +pub fn path_from_sql(mut buf: &[u8]) -> Result, StdBox> { let closed = buf.read_u8()? != 0; let points = buf.read_i32::()?; diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index da171cc79..111487173 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -760,8 +760,8 @@ impl<'a> UrlParser<'a> { fn remove_url_prefix(s: &str) -> Option<&str> { for prefix in &["postgres://", "postgresql://"] { - if s.starts_with(prefix) { - return Some(&s[prefix.len()..]); + if let Some(stripped) = s.strip_prefix(prefix) { + return Some(stripped); } } @@ -825,8 +825,8 @@ impl<'a> UrlParser<'a> { let host = &chunk[1..idx]; let remaining = &chunk[idx + 1..]; - let port = if remaining.starts_with(':') { - Some(&remaining[1..]) + let port = if let Some(port) = remaining.strip_prefix(':') { + Some(port) } else if remaining.is_empty() { None } else { diff --git a/tokio-postgres/src/connection.rs b/tokio-postgres/src/connection.rs index 9c8e369f1..b6805f76c 100644 --- a/tokio-postgres/src/connection.rs +++ b/tokio-postgres/src/connection.rs @@ -200,9 +200,10 @@ where return Ok(false); } - if let Poll::Pending = Pin::new(&mut self.stream) + if Pin::new(&mut self.stream) .poll_ready(cx) .map_err(Error::io)? + .is_pending() { trace!("poll_write: waiting on socket"); return Ok(false); diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index 11d128764..bc31ece71 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -483,11 +483,7 @@ async fn domain() { } fn accepts(ty: &Type) -> bool { - ty.name() == "session_id" - && match *ty.kind() { - Kind::Domain(_) => true, - _ => false, - } + ty.name() == "session_id" && matches!(ty.kind(), Kind::Domain(_)) } to_sql_checked!(); From ead071b87c5468a5208b4f0b262977e29a0d36fd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 16 Mar 2021 20:48:02 -0400 Subject: [PATCH 090/420] Remove readme badge --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 3af068174..b81a6716f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ # Rust-Postgres -[![CircleCI](https://circleci.com/gh/sfackler/rust-postgres.svg?style=shield)](https://circleci.com/gh/sfackler/rust-postgres) PostgreSQL support for Rust. From 49db9cd33c3e8deea195d43c2c0296baa48601bb Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 18 Mar 2021 20:39:43 -0400 Subject: [PATCH 091/420] upgrade socket2 --- tokio-postgres/Cargo.toml | 2 +- tokio-postgres/src/connect_socket.rs | 40 ++++++++++------------------ 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 254ebe62e..c03f87080 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -49,7 +49,7 @@ pin-project-lite = "0.2" phf = "0.8" postgres-protocol = { version = "0.6.0", path = "../postgres-protocol" } postgres-types = { version = "0.2.0", path = "../postgres-types" } -socket2 = "0.3" +socket2 = "0.4" tokio = { version = "1.0", features = ["io-util"] } tokio-util = { version = "0.6", features = ["codec"] } diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 564677b05..474676908 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -1,17 +1,12 @@ use crate::config::Host; use crate::{Error, Socket}; -use socket2::{Domain, Protocol, Type}; +use socket2::{SockRef, TcpKeepalive}; use std::future::Future; use std::io; -use std::net::SocketAddr; -#[cfg(unix)] -use std::os::unix::io::{FromRawFd, IntoRawFd}; -#[cfg(windows)] -use std::os::windows::io::{FromRawSocket, IntoRawSocket}; use std::time::Duration; #[cfg(unix)] use tokio::net::UnixStream; -use tokio::net::{self, TcpSocket}; +use tokio::net::{self, TcpStream}; use tokio::time; pub(crate) async fn connect_socket( @@ -30,30 +25,23 @@ pub(crate) async fn connect_socket( let mut last_err = None; for addr in addrs { - let domain = match addr { - SocketAddr::V4(_) => Domain::ipv4(), - SocketAddr::V6(_) => Domain::ipv6(), - }; + let stream = + match connect_with_timeout(TcpStream::connect(addr), connect_timeout).await { + Ok(stream) => stream, + Err(e) => { + last_err = Some(e); + continue; + } + }; - let socket = socket2::Socket::new(domain, Type::stream(), Some(Protocol::tcp())) - .map_err(Error::connect)?; - socket.set_nonblocking(true).map_err(Error::connect)?; - socket.set_nodelay(true).map_err(Error::connect)?; + stream.set_nodelay(true).map_err(Error::connect)?; if keepalives { - socket - .set_keepalive(Some(keepalives_idle)) + SockRef::from(&stream) + .set_tcp_keepalive(&TcpKeepalive::new().with_time(keepalives_idle)) .map_err(Error::connect)?; } - #[cfg(unix)] - let socket = unsafe { TcpSocket::from_raw_fd(socket.into_raw_fd()) }; - #[cfg(windows)] - let socket = unsafe { TcpSocket::from_raw_socket(socket.into_raw_socket()) }; - - match connect_with_timeout(socket.connect(addr), connect_timeout).await { - Ok(socket) => return Ok(Socket::new_tcp(socket)), - Err(e) => last_err = Some(e), - } + return Ok(Socket::new_tcp(stream)); } Err(last_err.unwrap_or_else(|| { From 39736a6244244bd74456eb94dc0e87a38e542331 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 18 Mar 2021 20:43:58 -0400 Subject: [PATCH 092/420] bump ci version to 1.46 --- .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 7191eb9e4..4a95dbe0c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,7 @@ jobs: - uses: actions/checkout@v2 - uses: sfackler/actions/rustup@master with: - version: 1.45.0 + version: 1.46.0 - run: echo "::set-output name=version::$(rustc --version)" id: rust-version - uses: actions/cache@v1 From 71cb6eef681ea6430cd723cd90fb45c90e6ac9d1 Mon Sep 17 00:00:00 2001 From: hansolshin Date: Sun, 28 Mar 2021 23:00:49 +0900 Subject: [PATCH 093/420] Add is_closed method to Error --- tokio-postgres/src/error/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tokio-postgres/src/error/mod.rs b/tokio-postgres/src/error/mod.rs index ee29a1dbb..47a31e793 100644 --- a/tokio-postgres/src/error/mod.rs +++ b/tokio-postgres/src/error/mod.rs @@ -421,6 +421,11 @@ impl Error { self.source().and_then(|e| e.downcast_ref::()) } + /// Determines if the error was associated with closed connection. + pub fn is_closed(&self) -> bool { + self.0.kind == Kind::Closed + } + /// Returns the SQLSTATE error code associated with the error. /// /// This is a convenience method that downcasts the cause to a `DbError` and returns its code. From af7825308d9808067dfa3af40571662d8c7a9592 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 28 Mar 2021 20:28:18 -0400 Subject: [PATCH 094/420] fix clippy --- tokio-postgres/tests/test/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index bf6d72d3e..e9439162b 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -577,7 +577,7 @@ async fn notices() { .unwrap(); let (tx, rx) = mpsc::unbounded(); - let stream = stream::poll_fn(move |cx| connection.poll_message(cx)).map_err(|e| panic!(e)); + let stream = stream::poll_fn(move |cx| connection.poll_message(cx)).map_err(|e| panic!("{}", e)); let connection = stream.forward(tx).map(|r| r.unwrap()); tokio::spawn(connection); @@ -612,7 +612,7 @@ async fn notifications() { let (client, mut connection) = connect_raw("user=postgres").await.unwrap(); let (tx, rx) = mpsc::unbounded(); - let stream = stream::poll_fn(move |cx| connection.poll_message(cx)).map_err(|e| panic!(e)); + let stream = stream::poll_fn(move |cx| connection.poll_message(cx)).map_err(|e| panic!("{}", e)); let connection = stream.forward(tx).map(|r| r.unwrap()); tokio::spawn(connection); From fc10985f9fdf0903893109bc951fb5891539bf97 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 28 Mar 2021 20:31:59 -0400 Subject: [PATCH 095/420] rustfmt --- tokio-postgres/tests/test/main.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index e9439162b..c367dbea3 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -577,7 +577,8 @@ async fn notices() { .unwrap(); let (tx, rx) = mpsc::unbounded(); - let stream = stream::poll_fn(move |cx| connection.poll_message(cx)).map_err(|e| panic!("{}", e)); + let stream = + stream::poll_fn(move |cx| connection.poll_message(cx)).map_err(|e| panic!("{}", e)); let connection = stream.forward(tx).map(|r| r.unwrap()); tokio::spawn(connection); @@ -612,7 +613,8 @@ async fn notifications() { let (client, mut connection) = connect_raw("user=postgres").await.unwrap(); let (tx, rx) = mpsc::unbounded(); - let stream = stream::poll_fn(move |cx| connection.poll_message(cx)).map_err(|e| panic!("{}", e)); + let stream = + stream::poll_fn(move |cx| connection.poll_message(cx)).map_err(|e| panic!("{}", e)); let connection = stream.forward(tx).map(|r| r.unwrap()); tokio::spawn(connection); From 558c169b8910dd6b6ab129995ab71fcd0d67fb66 Mon Sep 17 00:00:00 2001 From: Dmitriy Pleshevskiy Date: Thu, 1 Apr 2021 23:39:50 +0300 Subject: [PATCH 096/420] feat: add method to clear types cache Closes #753 --- tokio-postgres/src/client.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 359a7cd16..f11e5736b 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -113,6 +113,10 @@ impl InnerClient { self.state.lock().types.insert(oid, type_.clone()); } + pub fn clear_types(&self) { + self.state.lock().types.clear(); + } + pub fn with_buf(&self, f: F) -> R where F: FnOnce(&mut BytesMut) -> R, @@ -176,6 +180,11 @@ impl Client { &self.inner } + /// Clears the cache of database types (domain, enum, composition) that are loaded when preparing a query. + pub fn clear_types_cache(&self) { + self.inner().clear_types() + } + #[cfg(feature = "runtime")] pub(crate) fn set_socket_config(&mut self, socket_config: SocketConfig) { self.socket_config = Some(socket_config); From 844a27a074c9905832752b736073a4a68d616c7a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 3 Apr 2021 16:55:59 -0400 Subject: [PATCH 097/420] Add clear_type_cache to blocking client --- postgres/src/client.rs | 13 +++++++++++-- tokio-postgres/src/client.rs | 21 ++++++++++++--------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/postgres/src/client.rs b/postgres/src/client.rs index 0ff2376e1..29cac840d 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -501,8 +501,8 @@ impl Client { Notifications::new(self.connection.as_ref()) } - /// Constructs a cancellation token that can later be used to request - /// cancellation of a query running on this connection. + /// Constructs a cancellation token that can later be used to request cancellation of a query running on this + /// connection. /// /// # Examples /// @@ -541,6 +541,15 @@ impl Client { CancelToken::new(self.client.cancel_token()) } + /// Clears the client's type information cache. + /// + /// When user-defined types are used in a query, the client loads their definitions from the database and caches + /// them for the lifetime of the client. If those definitions are changed in the database, this method can be used + /// to flush the local cache and allow the new, updated definitions to be loaded. + pub fn clear_type_cache(&self) { + self.client.clear_type_cache(); + } + /// Determines if the client's connection has already closed. /// /// If this returns `true`, the client is no longer usable. diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index f11e5736b..f19005e55 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -113,7 +113,7 @@ impl InnerClient { self.state.lock().types.insert(oid, type_.clone()); } - pub fn clear_types(&self) { + pub fn clear_type_cache(&self) { self.state.lock().types.clear(); } @@ -180,11 +180,6 @@ impl Client { &self.inner } - /// Clears the cache of database types (domain, enum, composition) that are loaded when preparing a query. - pub fn clear_types_cache(&self) { - self.inner().clear_types() - } - #[cfg(feature = "runtime")] pub(crate) fn set_socket_config(&mut self, socket_config: SocketConfig) { self.socket_config = Some(socket_config); @@ -493,9 +488,8 @@ impl Client { TransactionBuilder::new(self) } - /// Constructs a cancellation token that can later be used to request - /// cancellation of a query running on the connection associated with - /// this client. + /// Constructs a cancellation token that can later be used to request cancellation of a query running on the + /// connection associated with this client. pub fn cancel_token(&self) -> CancelToken { CancelToken { #[cfg(feature = "runtime")] @@ -532,6 +526,15 @@ impl Client { self.cancel_token().cancel_query_raw(stream, tls).await } + /// Clears the client's type information cache. + /// + /// When user-defined types are used in a query, the client loads their definitions from the database and caches + /// them for the lifetime of the client. If those definitions are changed in the database, this method can be used + /// to flush the local cache and allow the new, updated definitions to be loaded. + pub fn clear_type_cache(&self) { + self.inner().clear_type_cache(); + } + /// Determines if the connection to the server has already closed. /// /// In that case, all future queries will fail. From a598c52906a432cd0670d8aba60a1dd174484ed8 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 3 Apr 2021 17:06:51 -0400 Subject: [PATCH 098/420] Release postgres-protocol v0.6.1 --- postgres-protocol/CHANGELOG.md | 11 +++++++++++ postgres-protocol/Cargo.toml | 2 +- postgres-protocol/src/lib.rs | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/postgres-protocol/CHANGELOG.md b/postgres-protocol/CHANGELOG.md index 4040c3ba2..7a51cb192 100644 --- a/postgres-protocol/CHANGELOG.md +++ b/postgres-protocol/CHANGELOG.md @@ -1,5 +1,16 @@ # Change Log +## v0.6.1 - 2021-04-03 + +### Added + +* Added the `password` module, which can be used to hash passwords before using them in queries like `ALTER USER`. +* Added type conversions for `LSN`. + +### Changed + +* Moved from `md5` to `md-5`. + ## v0.6.0 - 2020-12-25 ### Changed diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index 1224c633d..4fd288697 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-protocol" -version = "0.6.0" +version = "0.6.1" authors = ["Steven Fackler "] edition = "2018" description = "Low level Postgres protocol APIs" diff --git a/postgres-protocol/src/lib.rs b/postgres-protocol/src/lib.rs index c9fe0ee19..8b6ff508d 100644 --- a/postgres-protocol/src/lib.rs +++ b/postgres-protocol/src/lib.rs @@ -9,7 +9,7 @@ //! //! This library assumes that the `client_encoding` backend parameter has been //! set to `UTF8`. It will most likely not behave properly if that is not the case. -#![doc(html_root_url = "https://docs.rs/postgres-protocol/0.5")] +#![doc(html_root_url = "https://docs.rs/postgres-protocol/0.6")] #![warn(missing_docs, rust_2018_idioms, clippy::all)] use byteorder::{BigEndian, ByteOrder}; From 32524569c2dd0be0bbeb6ed8fd82fe2f33d77a01 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 3 Apr 2021 17:10:03 -0400 Subject: [PATCH 099/420] Release postgres-types v0.2.1 --- postgres-types/CHANGELOG.md | 3 ++- postgres-types/Cargo.toml | 4 ++-- postgres-types/src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index 9f9da7989..83bc4d1fd 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -1,10 +1,11 @@ # Change Log -## Unreleased +## v0.2.1 - 2021-04-03 ### Added * Added support for `geo-types` 0.7 via `with-geo-types-0_7` feature. +* Added the `PgLsn` type, corresponding to `PG_LSN`. ## v0.2.0 - 2020-12-25 diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 7d48596ae..1d7f2cc9a 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-types" -version = "0.2.0" +version = "0.2.1" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -24,7 +24,7 @@ with-time-0_2 = ["time-02"] [dependencies] bytes = "1.0" fallible-iterator = "0.2" -postgres-protocol = { version = "0.6.0", path = "../postgres-protocol" } +postgres-protocol = { version = "0.6.1", path = "../postgres-protocol" } postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-derive" } bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index e9a7c10a2..5c483bd76 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -105,7 +105,7 @@ //! Happy, //! } //! ``` -#![doc(html_root_url = "https://docs.rs/postgres-types/0.1")] +#![doc(html_root_url = "https://docs.rs/postgres-types/0.2")] #![warn(clippy::all, rust_2018_idioms, missing_docs)] use fallible_iterator::FallibleIterator; From 57164c7e59f31be016980e7874fd7b8a4c92d40a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 3 Apr 2021 17:12:50 -0400 Subject: [PATCH 100/420] Release tokio-postgres v0.7.1 --- tokio-postgres/CHANGELOG.md | 4 +++- tokio-postgres/Cargo.toml | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index db984ca18..7cc6c7071 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,10 +1,12 @@ # Change Log -## Unreleased +## v0.7.1 - 2020-04-03 ### Added * Added support for `geo-types` 0.7 via `with-geo-types-0_7` feature. +* Added `Client::clear_type_cache`. +* Added `Error::as_db_error` and `Error::is_closed`. ## v0.7.0 - 2020-12-25 diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index c03f87080..b1d093d4b 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.7.0" +version = "0.7.1" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -47,8 +47,8 @@ parking_lot = "0.11" percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.8" -postgres-protocol = { version = "0.6.0", path = "../postgres-protocol" } -postgres-types = { version = "0.2.0", path = "../postgres-types" } +postgres-protocol = { version = "0.6.1", path = "../postgres-protocol" } +postgres-types = { version = "0.2.1", path = "../postgres-types" } socket2 = "0.4" tokio = { version = "1.0", features = ["io-util"] } tokio-util = { version = "0.6", features = ["codec"] } From 2ab49f6c564f73eba1404c060e4ef5520ed6c798 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 3 Apr 2021 17:14:25 -0400 Subject: [PATCH 101/420] Release postgres v0.19.1 --- postgres/CHANGELOG.md | 3 ++- postgres/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index 66e66c6fb..e68dedc5b 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,10 +1,11 @@ # Change Log -## Unreleased +## v0.19.1 - 2021-04-03 ### Added * Added support for `geo-types` 0.7 via `with-geo-types-0_7` feature. +* Added `Client::clear_type_cache`. ## v0.19.0 - 2020-12-25 diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 0128f8a4e..18219782d 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.19.0" +version = "0.19.1" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -34,7 +34,7 @@ with-time-0_2 = ["tokio-postgres/with-time-0_2"] bytes = "1.0" fallible-iterator = "0.2" futures = "0.3" -tokio-postgres = { version = "0.7.0", path = "../tokio-postgres" } +tokio-postgres = { version = "0.7.1", path = "../tokio-postgres" } tokio = { version = "1.0", features = ["rt", "time"] } log = "0.4" From 50fa995cf9b0215a03585d358f27078086ed4bfc Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 5 Apr 2021 19:04:34 -0400 Subject: [PATCH 102/420] Reorder a bit --- tokio-postgres/src/generic_client.rs | 22 +++++++++++----------- tokio-postgres/src/transaction.rs | 10 +++++----- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tokio-postgres/src/generic_client.rs b/tokio-postgres/src/generic_client.rs index 911a587b6..b2a907558 100644 --- a/tokio-postgres/src/generic_client.rs +++ b/tokio-postgres/src/generic_client.rs @@ -12,9 +12,6 @@ mod private { /// This trait is "sealed", and cannot be implemented outside of this crate. #[async_trait] pub trait GenericClient: private::Sealed { - /// Get a reference to the underlying `Client` - fn client(&self) -> &Client; - /// Like `Client::execute`. async fn execute(&self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where @@ -71,16 +68,15 @@ pub trait GenericClient: private::Sealed { /// Like `Client::transaction`. async fn transaction(&mut self) -> Result, Error>; + + /// Returns a reference to the underlying `Client`. + fn client(&self) -> &Client; } impl private::Sealed for Client {} #[async_trait] impl GenericClient for Client { - fn client(&self) -> &Client { - self - } - async fn execute(&self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement + Sync + Send, @@ -152,6 +148,10 @@ impl GenericClient for Client { async fn transaction(&mut self) -> Result, Error> { self.transaction().await } + + fn client(&self) -> &Client { + self + } } impl private::Sealed for Transaction<'_> {} @@ -159,10 +159,6 @@ impl private::Sealed for Transaction<'_> {} #[async_trait] #[allow(clippy::needless_lifetimes)] impl GenericClient for Transaction<'_> { - fn client(&self) -> &Client { - self.client() - } - async fn execute(&self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement + Sync + Send, @@ -235,4 +231,8 @@ impl GenericClient for Transaction<'_> { async fn transaction<'a>(&'a mut self) -> Result, Error> { self.transaction().await } + + fn client(&self) -> &Client { + self.client() + } } diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index cf39d9186..7fadce069 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -64,11 +64,6 @@ impl<'a> Transaction<'a> { } } - /// Get a reference to the underlying `Client` - pub fn client(&self) -> &Client { - &self.client - } - /// Consumes the transaction, committing all changes made within it. pub async fn commit(mut self) -> Result<(), Error> { self.done = true; @@ -311,4 +306,9 @@ impl<'a> Transaction<'a> { done: false, }) } + + /// Returns a reference to the underlying `Client`. + pub fn client(&self) -> &Client { + &self.client + } } From c7a8adf2df589ee7add08f2aa5a56fcf3d5ee095 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 5 Apr 2021 19:07:27 -0400 Subject: [PATCH 103/420] remove unneeded ref --- tokio-postgres/src/transaction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index 7fadce069..a1aa7611f 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -309,6 +309,6 @@ impl<'a> Transaction<'a> { /// Returns a reference to the underlying `Client`. pub fn client(&self) -> &Client { - &self.client + self.client } } From 05a0643cc02e95a9c10ae7936e8941cbdb62e07f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 24 Apr 2021 10:19:23 -0400 Subject: [PATCH 104/420] Fix matching on SqlState Closes #756 --- codegen/src/sqlstate.rs | 68 +- tokio-postgres/src/error/sqlstate.rs | 1073 +++++++++++++++++++------- 2 files changed, 852 insertions(+), 289 deletions(-) diff --git a/codegen/src/sqlstate.rs b/codegen/src/sqlstate.rs index bb21be34f..ea3045654 100644 --- a/codegen/src/sqlstate.rs +++ b/codegen/src/sqlstate.rs @@ -1,5 +1,4 @@ use linked_hash_map::LinkedHashMap; -use phf_codegen; use std::fs::File; use std::io::{BufWriter, Write}; @@ -11,7 +10,9 @@ pub fn build() { let codes = parse_codes(); make_type(&mut file); + make_code(&codes, &mut file); make_consts(&codes, &mut file); + make_inner(&codes, &mut file); make_map(&codes, &mut file); } @@ -38,26 +39,51 @@ fn make_type(file: &mut BufWriter) { write!( file, "// Autogenerated file - DO NOT EDIT -use std::borrow::Cow; /// A SQLSTATE error code #[derive(PartialEq, Eq, Clone, Debug)] -pub struct SqlState(Cow<'static, str>); +pub struct SqlState(Inner); impl SqlState {{ /// Creates a `SqlState` from its error code. pub fn from_code(s: &str) -> SqlState {{ match SQLSTATE_MAP.get(s) {{ Some(state) => state.clone(), - None => SqlState(Cow::Owned(s.to_string())), + None => SqlState(Inner::Other(s.into())), }} }} +" + ) + .unwrap(); +} +fn make_code(codes: &LinkedHashMap>, file: &mut BufWriter) { + write!( + file, + r#" /// Returns the error code corresponding to the `SqlState`. pub fn code(&self) -> &str {{ - &self.0 + match &self.0 {{"#, + ) + .unwrap(); + + for code in codes.keys() { + write!( + file, + r#" + Inner::E{code} => "{code}","#, + code = code, + ) + .unwrap(); + } + + write!( + file, + r#" + Inner::Other(code) => code, + }} }} -" + "# ) .unwrap(); } @@ -69,7 +95,7 @@ fn make_consts(codes: &LinkedHashMap>, file: &mut BufWriter< file, r#" /// {code} - pub const {name}: SqlState = SqlState(Cow::Borrowed("{code}")); + pub const {name}: SqlState = SqlState(Inner::E{code}); "#, name = name, code = code, @@ -81,6 +107,34 @@ fn make_consts(codes: &LinkedHashMap>, file: &mut BufWriter< write!(file, "}}").unwrap(); } +fn make_inner(codes: &LinkedHashMap>, file: &mut BufWriter) { + write!( + file, + r#" + +#[derive(PartialEq, Eq, Clone, Debug)] +enum Inner {{"#, + ) + .unwrap(); + for code in codes.keys() { + write!( + file, + r#" + E{},"#, + code, + ) + .unwrap(); + } + write!( + file, + r#" + Other(Box), +}} + "#, + ) + .unwrap(); +} + fn make_map(codes: &LinkedHashMap>, file: &mut BufWriter) { let mut builder = phf_codegen::Map::new(); for (code, names) in codes { diff --git a/tokio-postgres/src/error/sqlstate.rs b/tokio-postgres/src/error/sqlstate.rs index 3a6ea0bdc..6505b51ce 100644 --- a/tokio-postgres/src/error/sqlstate.rs +++ b/tokio-postgres/src/error/sqlstate.rs @@ -1,832 +1,1341 @@ // Autogenerated file - DO NOT EDIT -use std::borrow::Cow; /// A SQLSTATE error code #[derive(PartialEq, Eq, Clone, Debug)] -pub struct SqlState(Cow<'static, str>); +pub struct SqlState(Inner); impl SqlState { /// Creates a `SqlState` from its error code. pub fn from_code(s: &str) -> SqlState { match SQLSTATE_MAP.get(s) { Some(state) => state.clone(), - None => SqlState(Cow::Owned(s.to_string())), + None => SqlState(Inner::Other(s.into())), } } /// Returns the error code corresponding to the `SqlState`. pub fn code(&self) -> &str { - &self.0 + match &self.0 { + Inner::E00000 => "00000", + Inner::E01000 => "01000", + Inner::E0100C => "0100C", + Inner::E01008 => "01008", + Inner::E01003 => "01003", + Inner::E01007 => "01007", + Inner::E01006 => "01006", + Inner::E01004 => "01004", + Inner::E01P01 => "01P01", + Inner::E02000 => "02000", + Inner::E02001 => "02001", + Inner::E03000 => "03000", + Inner::E08000 => "08000", + Inner::E08003 => "08003", + Inner::E08006 => "08006", + Inner::E08001 => "08001", + Inner::E08004 => "08004", + Inner::E08007 => "08007", + Inner::E08P01 => "08P01", + Inner::E09000 => "09000", + Inner::E0A000 => "0A000", + Inner::E0B000 => "0B000", + Inner::E0F000 => "0F000", + Inner::E0F001 => "0F001", + Inner::E0L000 => "0L000", + Inner::E0LP01 => "0LP01", + Inner::E0P000 => "0P000", + Inner::E0Z000 => "0Z000", + Inner::E0Z002 => "0Z002", + Inner::E20000 => "20000", + Inner::E21000 => "21000", + Inner::E22000 => "22000", + Inner::E2202E => "2202E", + Inner::E22021 => "22021", + Inner::E22008 => "22008", + Inner::E22012 => "22012", + Inner::E22005 => "22005", + Inner::E2200B => "2200B", + Inner::E22022 => "22022", + Inner::E22015 => "22015", + Inner::E2201E => "2201E", + Inner::E22014 => "22014", + Inner::E22016 => "22016", + Inner::E2201F => "2201F", + Inner::E2201G => "2201G", + Inner::E22018 => "22018", + Inner::E22007 => "22007", + Inner::E22019 => "22019", + Inner::E2200D => "2200D", + Inner::E22025 => "22025", + Inner::E22P06 => "22P06", + Inner::E22010 => "22010", + Inner::E22023 => "22023", + Inner::E22013 => "22013", + Inner::E2201B => "2201B", + Inner::E2201W => "2201W", + Inner::E2201X => "2201X", + Inner::E2202H => "2202H", + Inner::E2202G => "2202G", + Inner::E22009 => "22009", + Inner::E2200C => "2200C", + Inner::E2200G => "2200G", + Inner::E22004 => "22004", + Inner::E22002 => "22002", + Inner::E22003 => "22003", + Inner::E2200H => "2200H", + Inner::E22026 => "22026", + Inner::E22001 => "22001", + Inner::E22011 => "22011", + Inner::E22027 => "22027", + Inner::E22024 => "22024", + Inner::E2200F => "2200F", + Inner::E22P01 => "22P01", + Inner::E22P02 => "22P02", + Inner::E22P03 => "22P03", + Inner::E22P04 => "22P04", + Inner::E22P05 => "22P05", + Inner::E2200L => "2200L", + Inner::E2200M => "2200M", + Inner::E2200N => "2200N", + Inner::E2200S => "2200S", + Inner::E2200T => "2200T", + Inner::E22030 => "22030", + Inner::E22031 => "22031", + Inner::E22032 => "22032", + Inner::E22033 => "22033", + Inner::E22034 => "22034", + Inner::E22035 => "22035", + Inner::E22036 => "22036", + Inner::E22037 => "22037", + Inner::E22038 => "22038", + Inner::E22039 => "22039", + Inner::E2203A => "2203A", + Inner::E2203B => "2203B", + Inner::E2203C => "2203C", + Inner::E2203D => "2203D", + Inner::E2203E => "2203E", + Inner::E2203F => "2203F", + Inner::E23000 => "23000", + Inner::E23001 => "23001", + Inner::E23502 => "23502", + Inner::E23503 => "23503", + Inner::E23505 => "23505", + Inner::E23514 => "23514", + Inner::E23P01 => "23P01", + Inner::E24000 => "24000", + Inner::E25000 => "25000", + Inner::E25001 => "25001", + Inner::E25002 => "25002", + Inner::E25008 => "25008", + Inner::E25003 => "25003", + Inner::E25004 => "25004", + Inner::E25005 => "25005", + Inner::E25006 => "25006", + Inner::E25007 => "25007", + Inner::E25P01 => "25P01", + Inner::E25P02 => "25P02", + Inner::E25P03 => "25P03", + Inner::E26000 => "26000", + Inner::E27000 => "27000", + Inner::E28000 => "28000", + Inner::E28P01 => "28P01", + Inner::E2B000 => "2B000", + Inner::E2BP01 => "2BP01", + Inner::E2D000 => "2D000", + Inner::E2F000 => "2F000", + Inner::E2F005 => "2F005", + Inner::E2F002 => "2F002", + Inner::E2F003 => "2F003", + Inner::E2F004 => "2F004", + Inner::E34000 => "34000", + Inner::E38000 => "38000", + Inner::E38001 => "38001", + Inner::E38002 => "38002", + Inner::E38003 => "38003", + Inner::E38004 => "38004", + Inner::E39000 => "39000", + Inner::E39001 => "39001", + Inner::E39004 => "39004", + Inner::E39P01 => "39P01", + Inner::E39P02 => "39P02", + Inner::E39P03 => "39P03", + Inner::E3B000 => "3B000", + Inner::E3B001 => "3B001", + Inner::E3D000 => "3D000", + Inner::E3F000 => "3F000", + Inner::E40000 => "40000", + Inner::E40002 => "40002", + Inner::E40001 => "40001", + Inner::E40003 => "40003", + Inner::E40P01 => "40P01", + Inner::E42000 => "42000", + Inner::E42601 => "42601", + Inner::E42501 => "42501", + Inner::E42846 => "42846", + Inner::E42803 => "42803", + Inner::E42P20 => "42P20", + Inner::E42P19 => "42P19", + Inner::E42830 => "42830", + Inner::E42602 => "42602", + Inner::E42622 => "42622", + Inner::E42939 => "42939", + Inner::E42804 => "42804", + Inner::E42P18 => "42P18", + Inner::E42P21 => "42P21", + Inner::E42P22 => "42P22", + Inner::E42809 => "42809", + Inner::E428C9 => "428C9", + Inner::E42703 => "42703", + Inner::E42883 => "42883", + Inner::E42P01 => "42P01", + Inner::E42P02 => "42P02", + Inner::E42704 => "42704", + Inner::E42701 => "42701", + Inner::E42P03 => "42P03", + Inner::E42P04 => "42P04", + Inner::E42723 => "42723", + Inner::E42P05 => "42P05", + Inner::E42P06 => "42P06", + Inner::E42P07 => "42P07", + Inner::E42712 => "42712", + Inner::E42710 => "42710", + Inner::E42702 => "42702", + Inner::E42725 => "42725", + Inner::E42P08 => "42P08", + Inner::E42P09 => "42P09", + Inner::E42P10 => "42P10", + Inner::E42611 => "42611", + Inner::E42P11 => "42P11", + Inner::E42P12 => "42P12", + Inner::E42P13 => "42P13", + Inner::E42P14 => "42P14", + Inner::E42P15 => "42P15", + Inner::E42P16 => "42P16", + Inner::E42P17 => "42P17", + Inner::E44000 => "44000", + Inner::E53000 => "53000", + Inner::E53100 => "53100", + Inner::E53200 => "53200", + Inner::E53300 => "53300", + Inner::E53400 => "53400", + Inner::E54000 => "54000", + Inner::E54001 => "54001", + Inner::E54011 => "54011", + Inner::E54023 => "54023", + Inner::E55000 => "55000", + Inner::E55006 => "55006", + Inner::E55P02 => "55P02", + Inner::E55P03 => "55P03", + Inner::E55P04 => "55P04", + Inner::E57000 => "57000", + Inner::E57014 => "57014", + Inner::E57P01 => "57P01", + Inner::E57P02 => "57P02", + Inner::E57P03 => "57P03", + Inner::E57P04 => "57P04", + Inner::E58000 => "58000", + Inner::E58030 => "58030", + Inner::E58P01 => "58P01", + Inner::E58P02 => "58P02", + Inner::E72000 => "72000", + Inner::EF0000 => "F0000", + Inner::EF0001 => "F0001", + Inner::EHV000 => "HV000", + Inner::EHV005 => "HV005", + Inner::EHV002 => "HV002", + Inner::EHV010 => "HV010", + Inner::EHV021 => "HV021", + Inner::EHV024 => "HV024", + Inner::EHV007 => "HV007", + Inner::EHV008 => "HV008", + Inner::EHV004 => "HV004", + Inner::EHV006 => "HV006", + Inner::EHV091 => "HV091", + Inner::EHV00B => "HV00B", + Inner::EHV00C => "HV00C", + Inner::EHV00D => "HV00D", + Inner::EHV090 => "HV090", + Inner::EHV00A => "HV00A", + Inner::EHV009 => "HV009", + Inner::EHV014 => "HV014", + Inner::EHV001 => "HV001", + Inner::EHV00P => "HV00P", + Inner::EHV00J => "HV00J", + Inner::EHV00K => "HV00K", + Inner::EHV00Q => "HV00Q", + Inner::EHV00R => "HV00R", + Inner::EHV00L => "HV00L", + Inner::EHV00M => "HV00M", + Inner::EHV00N => "HV00N", + Inner::EP0000 => "P0000", + Inner::EP0001 => "P0001", + Inner::EP0002 => "P0002", + Inner::EP0003 => "P0003", + Inner::EP0004 => "P0004", + Inner::EXX000 => "XX000", + Inner::EXX001 => "XX001", + Inner::EXX002 => "XX002", + Inner::Other(code) => code, + } } /// 00000 - pub const SUCCESSFUL_COMPLETION: SqlState = SqlState(Cow::Borrowed("00000")); + pub const SUCCESSFUL_COMPLETION: SqlState = SqlState(Inner::E00000); /// 01000 - pub const WARNING: SqlState = SqlState(Cow::Borrowed("01000")); + pub const WARNING: SqlState = SqlState(Inner::E01000); /// 0100C - pub const WARNING_DYNAMIC_RESULT_SETS_RETURNED: SqlState = SqlState(Cow::Borrowed("0100C")); + pub const WARNING_DYNAMIC_RESULT_SETS_RETURNED: SqlState = SqlState(Inner::E0100C); /// 01008 - pub const WARNING_IMPLICIT_ZERO_BIT_PADDING: SqlState = SqlState(Cow::Borrowed("01008")); + pub const WARNING_IMPLICIT_ZERO_BIT_PADDING: SqlState = SqlState(Inner::E01008); /// 01003 - pub const WARNING_NULL_VALUE_ELIMINATED_IN_SET_FUNCTION: SqlState = - SqlState(Cow::Borrowed("01003")); + pub const WARNING_NULL_VALUE_ELIMINATED_IN_SET_FUNCTION: SqlState = SqlState(Inner::E01003); /// 01007 - pub const WARNING_PRIVILEGE_NOT_GRANTED: SqlState = SqlState(Cow::Borrowed("01007")); + pub const WARNING_PRIVILEGE_NOT_GRANTED: SqlState = SqlState(Inner::E01007); /// 01006 - pub const WARNING_PRIVILEGE_NOT_REVOKED: SqlState = SqlState(Cow::Borrowed("01006")); + pub const WARNING_PRIVILEGE_NOT_REVOKED: SqlState = SqlState(Inner::E01006); /// 01004 - pub const WARNING_STRING_DATA_RIGHT_TRUNCATION: SqlState = SqlState(Cow::Borrowed("01004")); + pub const WARNING_STRING_DATA_RIGHT_TRUNCATION: SqlState = SqlState(Inner::E01004); /// 01P01 - pub const WARNING_DEPRECATED_FEATURE: SqlState = SqlState(Cow::Borrowed("01P01")); + pub const WARNING_DEPRECATED_FEATURE: SqlState = SqlState(Inner::E01P01); /// 02000 - pub const NO_DATA: SqlState = SqlState(Cow::Borrowed("02000")); + pub const NO_DATA: SqlState = SqlState(Inner::E02000); /// 02001 - pub const NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED: SqlState = - SqlState(Cow::Borrowed("02001")); + pub const NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED: SqlState = SqlState(Inner::E02001); /// 03000 - pub const SQL_STATEMENT_NOT_YET_COMPLETE: SqlState = SqlState(Cow::Borrowed("03000")); + pub const SQL_STATEMENT_NOT_YET_COMPLETE: SqlState = SqlState(Inner::E03000); /// 08000 - pub const CONNECTION_EXCEPTION: SqlState = SqlState(Cow::Borrowed("08000")); + pub const CONNECTION_EXCEPTION: SqlState = SqlState(Inner::E08000); /// 08003 - pub const CONNECTION_DOES_NOT_EXIST: SqlState = SqlState(Cow::Borrowed("08003")); + pub const CONNECTION_DOES_NOT_EXIST: SqlState = SqlState(Inner::E08003); /// 08006 - pub const CONNECTION_FAILURE: SqlState = SqlState(Cow::Borrowed("08006")); + pub const CONNECTION_FAILURE: SqlState = SqlState(Inner::E08006); /// 08001 - pub const SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION: SqlState = - SqlState(Cow::Borrowed("08001")); + pub const SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION: SqlState = SqlState(Inner::E08001); /// 08004 - pub const SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION: SqlState = - SqlState(Cow::Borrowed("08004")); + pub const SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION: SqlState = SqlState(Inner::E08004); /// 08007 - pub const TRANSACTION_RESOLUTION_UNKNOWN: SqlState = SqlState(Cow::Borrowed("08007")); + pub const TRANSACTION_RESOLUTION_UNKNOWN: SqlState = SqlState(Inner::E08007); /// 08P01 - pub const PROTOCOL_VIOLATION: SqlState = SqlState(Cow::Borrowed("08P01")); + pub const PROTOCOL_VIOLATION: SqlState = SqlState(Inner::E08P01); /// 09000 - pub const TRIGGERED_ACTION_EXCEPTION: SqlState = SqlState(Cow::Borrowed("09000")); + pub const TRIGGERED_ACTION_EXCEPTION: SqlState = SqlState(Inner::E09000); /// 0A000 - pub const FEATURE_NOT_SUPPORTED: SqlState = SqlState(Cow::Borrowed("0A000")); + pub const FEATURE_NOT_SUPPORTED: SqlState = SqlState(Inner::E0A000); /// 0B000 - pub const INVALID_TRANSACTION_INITIATION: SqlState = SqlState(Cow::Borrowed("0B000")); + pub const INVALID_TRANSACTION_INITIATION: SqlState = SqlState(Inner::E0B000); /// 0F000 - pub const LOCATOR_EXCEPTION: SqlState = SqlState(Cow::Borrowed("0F000")); + pub const LOCATOR_EXCEPTION: SqlState = SqlState(Inner::E0F000); /// 0F001 - pub const L_E_INVALID_SPECIFICATION: SqlState = SqlState(Cow::Borrowed("0F001")); + pub const L_E_INVALID_SPECIFICATION: SqlState = SqlState(Inner::E0F001); /// 0L000 - pub const INVALID_GRANTOR: SqlState = SqlState(Cow::Borrowed("0L000")); + pub const INVALID_GRANTOR: SqlState = SqlState(Inner::E0L000); /// 0LP01 - pub const INVALID_GRANT_OPERATION: SqlState = SqlState(Cow::Borrowed("0LP01")); + pub const INVALID_GRANT_OPERATION: SqlState = SqlState(Inner::E0LP01); /// 0P000 - pub const INVALID_ROLE_SPECIFICATION: SqlState = SqlState(Cow::Borrowed("0P000")); + pub const INVALID_ROLE_SPECIFICATION: SqlState = SqlState(Inner::E0P000); /// 0Z000 - pub const DIAGNOSTICS_EXCEPTION: SqlState = SqlState(Cow::Borrowed("0Z000")); + pub const DIAGNOSTICS_EXCEPTION: SqlState = SqlState(Inner::E0Z000); /// 0Z002 pub const STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER: SqlState = - SqlState(Cow::Borrowed("0Z002")); + SqlState(Inner::E0Z002); /// 20000 - pub const CASE_NOT_FOUND: SqlState = SqlState(Cow::Borrowed("20000")); + pub const CASE_NOT_FOUND: SqlState = SqlState(Inner::E20000); /// 21000 - pub const CARDINALITY_VIOLATION: SqlState = SqlState(Cow::Borrowed("21000")); + pub const CARDINALITY_VIOLATION: SqlState = SqlState(Inner::E21000); /// 22000 - pub const DATA_EXCEPTION: SqlState = SqlState(Cow::Borrowed("22000")); + pub const DATA_EXCEPTION: SqlState = SqlState(Inner::E22000); /// 2202E - pub const ARRAY_ELEMENT_ERROR: SqlState = SqlState(Cow::Borrowed("2202E")); + pub const ARRAY_ELEMENT_ERROR: SqlState = SqlState(Inner::E2202E); /// 2202E - pub const ARRAY_SUBSCRIPT_ERROR: SqlState = SqlState(Cow::Borrowed("2202E")); + pub const ARRAY_SUBSCRIPT_ERROR: SqlState = SqlState(Inner::E2202E); /// 22021 - pub const CHARACTER_NOT_IN_REPERTOIRE: SqlState = SqlState(Cow::Borrowed("22021")); + pub const CHARACTER_NOT_IN_REPERTOIRE: SqlState = SqlState(Inner::E22021); /// 22008 - pub const DATETIME_FIELD_OVERFLOW: SqlState = SqlState(Cow::Borrowed("22008")); + pub const DATETIME_FIELD_OVERFLOW: SqlState = SqlState(Inner::E22008); /// 22008 - pub const DATETIME_VALUE_OUT_OF_RANGE: SqlState = SqlState(Cow::Borrowed("22008")); + pub const DATETIME_VALUE_OUT_OF_RANGE: SqlState = SqlState(Inner::E22008); /// 22012 - pub const DIVISION_BY_ZERO: SqlState = SqlState(Cow::Borrowed("22012")); + pub const DIVISION_BY_ZERO: SqlState = SqlState(Inner::E22012); /// 22005 - pub const ERROR_IN_ASSIGNMENT: SqlState = SqlState(Cow::Borrowed("22005")); + pub const ERROR_IN_ASSIGNMENT: SqlState = SqlState(Inner::E22005); /// 2200B - pub const ESCAPE_CHARACTER_CONFLICT: SqlState = SqlState(Cow::Borrowed("2200B")); + pub const ESCAPE_CHARACTER_CONFLICT: SqlState = SqlState(Inner::E2200B); /// 22022 - pub const INDICATOR_OVERFLOW: SqlState = SqlState(Cow::Borrowed("22022")); + pub const INDICATOR_OVERFLOW: SqlState = SqlState(Inner::E22022); /// 22015 - pub const INTERVAL_FIELD_OVERFLOW: SqlState = SqlState(Cow::Borrowed("22015")); + pub const INTERVAL_FIELD_OVERFLOW: SqlState = SqlState(Inner::E22015); /// 2201E - pub const INVALID_ARGUMENT_FOR_LOG: SqlState = SqlState(Cow::Borrowed("2201E")); + pub const INVALID_ARGUMENT_FOR_LOG: SqlState = SqlState(Inner::E2201E); /// 22014 - pub const INVALID_ARGUMENT_FOR_NTILE: SqlState = SqlState(Cow::Borrowed("22014")); + pub const INVALID_ARGUMENT_FOR_NTILE: SqlState = SqlState(Inner::E22014); /// 22016 - pub const INVALID_ARGUMENT_FOR_NTH_VALUE: SqlState = SqlState(Cow::Borrowed("22016")); + pub const INVALID_ARGUMENT_FOR_NTH_VALUE: SqlState = SqlState(Inner::E22016); /// 2201F - pub const INVALID_ARGUMENT_FOR_POWER_FUNCTION: SqlState = SqlState(Cow::Borrowed("2201F")); + pub const INVALID_ARGUMENT_FOR_POWER_FUNCTION: SqlState = SqlState(Inner::E2201F); /// 2201G - pub const INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION: SqlState = - SqlState(Cow::Borrowed("2201G")); + pub const INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION: SqlState = SqlState(Inner::E2201G); /// 22018 - pub const INVALID_CHARACTER_VALUE_FOR_CAST: SqlState = SqlState(Cow::Borrowed("22018")); + pub const INVALID_CHARACTER_VALUE_FOR_CAST: SqlState = SqlState(Inner::E22018); /// 22007 - pub const INVALID_DATETIME_FORMAT: SqlState = SqlState(Cow::Borrowed("22007")); + pub const INVALID_DATETIME_FORMAT: SqlState = SqlState(Inner::E22007); /// 22019 - pub const INVALID_ESCAPE_CHARACTER: SqlState = SqlState(Cow::Borrowed("22019")); + pub const INVALID_ESCAPE_CHARACTER: SqlState = SqlState(Inner::E22019); /// 2200D - pub const INVALID_ESCAPE_OCTET: SqlState = SqlState(Cow::Borrowed("2200D")); + pub const INVALID_ESCAPE_OCTET: SqlState = SqlState(Inner::E2200D); /// 22025 - pub const INVALID_ESCAPE_SEQUENCE: SqlState = SqlState(Cow::Borrowed("22025")); + pub const INVALID_ESCAPE_SEQUENCE: SqlState = SqlState(Inner::E22025); /// 22P06 - pub const NONSTANDARD_USE_OF_ESCAPE_CHARACTER: SqlState = SqlState(Cow::Borrowed("22P06")); + pub const NONSTANDARD_USE_OF_ESCAPE_CHARACTER: SqlState = SqlState(Inner::E22P06); /// 22010 - pub const INVALID_INDICATOR_PARAMETER_VALUE: SqlState = SqlState(Cow::Borrowed("22010")); + pub const INVALID_INDICATOR_PARAMETER_VALUE: SqlState = SqlState(Inner::E22010); /// 22023 - pub const INVALID_PARAMETER_VALUE: SqlState = SqlState(Cow::Borrowed("22023")); + pub const INVALID_PARAMETER_VALUE: SqlState = SqlState(Inner::E22023); /// 22013 - pub const INVALID_PRECEDING_OR_FOLLOWING_SIZE: SqlState = SqlState(Cow::Borrowed("22013")); + pub const INVALID_PRECEDING_OR_FOLLOWING_SIZE: SqlState = SqlState(Inner::E22013); /// 2201B - pub const INVALID_REGULAR_EXPRESSION: SqlState = SqlState(Cow::Borrowed("2201B")); + pub const INVALID_REGULAR_EXPRESSION: SqlState = SqlState(Inner::E2201B); /// 2201W - pub const INVALID_ROW_COUNT_IN_LIMIT_CLAUSE: SqlState = SqlState(Cow::Borrowed("2201W")); + pub const INVALID_ROW_COUNT_IN_LIMIT_CLAUSE: SqlState = SqlState(Inner::E2201W); /// 2201X - pub const INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE: SqlState = - SqlState(Cow::Borrowed("2201X")); + pub const INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE: SqlState = SqlState(Inner::E2201X); /// 2202H - pub const INVALID_TABLESAMPLE_ARGUMENT: SqlState = SqlState(Cow::Borrowed("2202H")); + pub const INVALID_TABLESAMPLE_ARGUMENT: SqlState = SqlState(Inner::E2202H); /// 2202G - pub const INVALID_TABLESAMPLE_REPEAT: SqlState = SqlState(Cow::Borrowed("2202G")); + pub const INVALID_TABLESAMPLE_REPEAT: SqlState = SqlState(Inner::E2202G); /// 22009 - pub const INVALID_TIME_ZONE_DISPLACEMENT_VALUE: SqlState = SqlState(Cow::Borrowed("22009")); + pub const INVALID_TIME_ZONE_DISPLACEMENT_VALUE: SqlState = SqlState(Inner::E22009); /// 2200C - pub const INVALID_USE_OF_ESCAPE_CHARACTER: SqlState = SqlState(Cow::Borrowed("2200C")); + pub const INVALID_USE_OF_ESCAPE_CHARACTER: SqlState = SqlState(Inner::E2200C); /// 2200G - pub const MOST_SPECIFIC_TYPE_MISMATCH: SqlState = SqlState(Cow::Borrowed("2200G")); + pub const MOST_SPECIFIC_TYPE_MISMATCH: SqlState = SqlState(Inner::E2200G); /// 22004 - pub const NULL_VALUE_NOT_ALLOWED: SqlState = SqlState(Cow::Borrowed("22004")); + pub const NULL_VALUE_NOT_ALLOWED: SqlState = SqlState(Inner::E22004); /// 22002 - pub const NULL_VALUE_NO_INDICATOR_PARAMETER: SqlState = SqlState(Cow::Borrowed("22002")); + pub const NULL_VALUE_NO_INDICATOR_PARAMETER: SqlState = SqlState(Inner::E22002); /// 22003 - pub const NUMERIC_VALUE_OUT_OF_RANGE: SqlState = SqlState(Cow::Borrowed("22003")); + pub const NUMERIC_VALUE_OUT_OF_RANGE: SqlState = SqlState(Inner::E22003); /// 2200H - pub const SEQUENCE_GENERATOR_LIMIT_EXCEEDED: SqlState = SqlState(Cow::Borrowed("2200H")); + pub const SEQUENCE_GENERATOR_LIMIT_EXCEEDED: SqlState = SqlState(Inner::E2200H); /// 22026 - pub const STRING_DATA_LENGTH_MISMATCH: SqlState = SqlState(Cow::Borrowed("22026")); + pub const STRING_DATA_LENGTH_MISMATCH: SqlState = SqlState(Inner::E22026); /// 22001 - pub const STRING_DATA_RIGHT_TRUNCATION: SqlState = SqlState(Cow::Borrowed("22001")); + pub const STRING_DATA_RIGHT_TRUNCATION: SqlState = SqlState(Inner::E22001); /// 22011 - pub const SUBSTRING_ERROR: SqlState = SqlState(Cow::Borrowed("22011")); + pub const SUBSTRING_ERROR: SqlState = SqlState(Inner::E22011); /// 22027 - pub const TRIM_ERROR: SqlState = SqlState(Cow::Borrowed("22027")); + pub const TRIM_ERROR: SqlState = SqlState(Inner::E22027); /// 22024 - pub const UNTERMINATED_C_STRING: SqlState = SqlState(Cow::Borrowed("22024")); + pub const UNTERMINATED_C_STRING: SqlState = SqlState(Inner::E22024); /// 2200F - pub const ZERO_LENGTH_CHARACTER_STRING: SqlState = SqlState(Cow::Borrowed("2200F")); + pub const ZERO_LENGTH_CHARACTER_STRING: SqlState = SqlState(Inner::E2200F); /// 22P01 - pub const FLOATING_POINT_EXCEPTION: SqlState = SqlState(Cow::Borrowed("22P01")); + pub const FLOATING_POINT_EXCEPTION: SqlState = SqlState(Inner::E22P01); /// 22P02 - pub const INVALID_TEXT_REPRESENTATION: SqlState = SqlState(Cow::Borrowed("22P02")); + pub const INVALID_TEXT_REPRESENTATION: SqlState = SqlState(Inner::E22P02); /// 22P03 - pub const INVALID_BINARY_REPRESENTATION: SqlState = SqlState(Cow::Borrowed("22P03")); + pub const INVALID_BINARY_REPRESENTATION: SqlState = SqlState(Inner::E22P03); /// 22P04 - pub const BAD_COPY_FILE_FORMAT: SqlState = SqlState(Cow::Borrowed("22P04")); + pub const BAD_COPY_FILE_FORMAT: SqlState = SqlState(Inner::E22P04); /// 22P05 - pub const UNTRANSLATABLE_CHARACTER: SqlState = SqlState(Cow::Borrowed("22P05")); + pub const UNTRANSLATABLE_CHARACTER: SqlState = SqlState(Inner::E22P05); /// 2200L - pub const NOT_AN_XML_DOCUMENT: SqlState = SqlState(Cow::Borrowed("2200L")); + pub const NOT_AN_XML_DOCUMENT: SqlState = SqlState(Inner::E2200L); /// 2200M - pub const INVALID_XML_DOCUMENT: SqlState = SqlState(Cow::Borrowed("2200M")); + pub const INVALID_XML_DOCUMENT: SqlState = SqlState(Inner::E2200M); /// 2200N - pub const INVALID_XML_CONTENT: SqlState = SqlState(Cow::Borrowed("2200N")); + pub const INVALID_XML_CONTENT: SqlState = SqlState(Inner::E2200N); /// 2200S - pub const INVALID_XML_COMMENT: SqlState = SqlState(Cow::Borrowed("2200S")); + pub const INVALID_XML_COMMENT: SqlState = SqlState(Inner::E2200S); /// 2200T - pub const INVALID_XML_PROCESSING_INSTRUCTION: SqlState = SqlState(Cow::Borrowed("2200T")); + pub const INVALID_XML_PROCESSING_INSTRUCTION: SqlState = SqlState(Inner::E2200T); /// 22030 - pub const DUPLICATE_JSON_OBJECT_KEY_VALUE: SqlState = SqlState(Cow::Borrowed("22030")); + pub const DUPLICATE_JSON_OBJECT_KEY_VALUE: SqlState = SqlState(Inner::E22030); /// 22031 - pub const INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION: SqlState = - SqlState(Cow::Borrowed("22031")); + pub const INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION: SqlState = SqlState(Inner::E22031); /// 22032 - pub const INVALID_JSON_TEXT: SqlState = SqlState(Cow::Borrowed("22032")); + pub const INVALID_JSON_TEXT: SqlState = SqlState(Inner::E22032); /// 22033 - pub const INVALID_SQL_JSON_SUBSCRIPT: SqlState = SqlState(Cow::Borrowed("22033")); + pub const INVALID_SQL_JSON_SUBSCRIPT: SqlState = SqlState(Inner::E22033); /// 22034 - pub const MORE_THAN_ONE_SQL_JSON_ITEM: SqlState = SqlState(Cow::Borrowed("22034")); + pub const MORE_THAN_ONE_SQL_JSON_ITEM: SqlState = SqlState(Inner::E22034); /// 22035 - pub const NO_SQL_JSON_ITEM: SqlState = SqlState(Cow::Borrowed("22035")); + pub const NO_SQL_JSON_ITEM: SqlState = SqlState(Inner::E22035); /// 22036 - pub const NON_NUMERIC_SQL_JSON_ITEM: SqlState = SqlState(Cow::Borrowed("22036")); + pub const NON_NUMERIC_SQL_JSON_ITEM: SqlState = SqlState(Inner::E22036); /// 22037 - pub const NON_UNIQUE_KEYS_IN_A_JSON_OBJECT: SqlState = SqlState(Cow::Borrowed("22037")); + pub const NON_UNIQUE_KEYS_IN_A_JSON_OBJECT: SqlState = SqlState(Inner::E22037); /// 22038 - pub const SINGLETON_SQL_JSON_ITEM_REQUIRED: SqlState = SqlState(Cow::Borrowed("22038")); + pub const SINGLETON_SQL_JSON_ITEM_REQUIRED: SqlState = SqlState(Inner::E22038); /// 22039 - pub const SQL_JSON_ARRAY_NOT_FOUND: SqlState = SqlState(Cow::Borrowed("22039")); + pub const SQL_JSON_ARRAY_NOT_FOUND: SqlState = SqlState(Inner::E22039); /// 2203A - pub const SQL_JSON_MEMBER_NOT_FOUND: SqlState = SqlState(Cow::Borrowed("2203A")); + pub const SQL_JSON_MEMBER_NOT_FOUND: SqlState = SqlState(Inner::E2203A); /// 2203B - pub const SQL_JSON_NUMBER_NOT_FOUND: SqlState = SqlState(Cow::Borrowed("2203B")); + pub const SQL_JSON_NUMBER_NOT_FOUND: SqlState = SqlState(Inner::E2203B); /// 2203C - pub const SQL_JSON_OBJECT_NOT_FOUND: SqlState = SqlState(Cow::Borrowed("2203C")); + pub const SQL_JSON_OBJECT_NOT_FOUND: SqlState = SqlState(Inner::E2203C); /// 2203D - pub const TOO_MANY_JSON_ARRAY_ELEMENTS: SqlState = SqlState(Cow::Borrowed("2203D")); + pub const TOO_MANY_JSON_ARRAY_ELEMENTS: SqlState = SqlState(Inner::E2203D); /// 2203E - pub const TOO_MANY_JSON_OBJECT_MEMBERS: SqlState = SqlState(Cow::Borrowed("2203E")); + pub const TOO_MANY_JSON_OBJECT_MEMBERS: SqlState = SqlState(Inner::E2203E); /// 2203F - pub const SQL_JSON_SCALAR_REQUIRED: SqlState = SqlState(Cow::Borrowed("2203F")); + pub const SQL_JSON_SCALAR_REQUIRED: SqlState = SqlState(Inner::E2203F); /// 23000 - pub const INTEGRITY_CONSTRAINT_VIOLATION: SqlState = SqlState(Cow::Borrowed("23000")); + pub const INTEGRITY_CONSTRAINT_VIOLATION: SqlState = SqlState(Inner::E23000); /// 23001 - pub const RESTRICT_VIOLATION: SqlState = SqlState(Cow::Borrowed("23001")); + pub const RESTRICT_VIOLATION: SqlState = SqlState(Inner::E23001); /// 23502 - pub const NOT_NULL_VIOLATION: SqlState = SqlState(Cow::Borrowed("23502")); + pub const NOT_NULL_VIOLATION: SqlState = SqlState(Inner::E23502); /// 23503 - pub const FOREIGN_KEY_VIOLATION: SqlState = SqlState(Cow::Borrowed("23503")); + pub const FOREIGN_KEY_VIOLATION: SqlState = SqlState(Inner::E23503); /// 23505 - pub const UNIQUE_VIOLATION: SqlState = SqlState(Cow::Borrowed("23505")); + pub const UNIQUE_VIOLATION: SqlState = SqlState(Inner::E23505); /// 23514 - pub const CHECK_VIOLATION: SqlState = SqlState(Cow::Borrowed("23514")); + pub const CHECK_VIOLATION: SqlState = SqlState(Inner::E23514); /// 23P01 - pub const EXCLUSION_VIOLATION: SqlState = SqlState(Cow::Borrowed("23P01")); + pub const EXCLUSION_VIOLATION: SqlState = SqlState(Inner::E23P01); /// 24000 - pub const INVALID_CURSOR_STATE: SqlState = SqlState(Cow::Borrowed("24000")); + pub const INVALID_CURSOR_STATE: SqlState = SqlState(Inner::E24000); /// 25000 - pub const INVALID_TRANSACTION_STATE: SqlState = SqlState(Cow::Borrowed("25000")); + pub const INVALID_TRANSACTION_STATE: SqlState = SqlState(Inner::E25000); /// 25001 - pub const ACTIVE_SQL_TRANSACTION: SqlState = SqlState(Cow::Borrowed("25001")); + pub const ACTIVE_SQL_TRANSACTION: SqlState = SqlState(Inner::E25001); /// 25002 - pub const BRANCH_TRANSACTION_ALREADY_ACTIVE: SqlState = SqlState(Cow::Borrowed("25002")); + pub const BRANCH_TRANSACTION_ALREADY_ACTIVE: SqlState = SqlState(Inner::E25002); /// 25008 - pub const HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL: SqlState = - SqlState(Cow::Borrowed("25008")); + pub const HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL: SqlState = SqlState(Inner::E25008); /// 25003 - pub const INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION: SqlState = - SqlState(Cow::Borrowed("25003")); + pub const INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION: SqlState = SqlState(Inner::E25003); /// 25004 pub const INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION: SqlState = - SqlState(Cow::Borrowed("25004")); + SqlState(Inner::E25004); /// 25005 - pub const NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION: SqlState = - SqlState(Cow::Borrowed("25005")); + pub const NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION: SqlState = SqlState(Inner::E25005); /// 25006 - pub const READ_ONLY_SQL_TRANSACTION: SqlState = SqlState(Cow::Borrowed("25006")); + pub const READ_ONLY_SQL_TRANSACTION: SqlState = SqlState(Inner::E25006); /// 25007 - pub const SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED: SqlState = - SqlState(Cow::Borrowed("25007")); + pub const SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED: SqlState = SqlState(Inner::E25007); /// 25P01 - pub const NO_ACTIVE_SQL_TRANSACTION: SqlState = SqlState(Cow::Borrowed("25P01")); + pub const NO_ACTIVE_SQL_TRANSACTION: SqlState = SqlState(Inner::E25P01); /// 25P02 - pub const IN_FAILED_SQL_TRANSACTION: SqlState = SqlState(Cow::Borrowed("25P02")); + pub const IN_FAILED_SQL_TRANSACTION: SqlState = SqlState(Inner::E25P02); /// 25P03 - pub const IDLE_IN_TRANSACTION_SESSION_TIMEOUT: SqlState = SqlState(Cow::Borrowed("25P03")); + pub const IDLE_IN_TRANSACTION_SESSION_TIMEOUT: SqlState = SqlState(Inner::E25P03); /// 26000 - pub const INVALID_SQL_STATEMENT_NAME: SqlState = SqlState(Cow::Borrowed("26000")); + pub const INVALID_SQL_STATEMENT_NAME: SqlState = SqlState(Inner::E26000); /// 26000 - pub const UNDEFINED_PSTATEMENT: SqlState = SqlState(Cow::Borrowed("26000")); + pub const UNDEFINED_PSTATEMENT: SqlState = SqlState(Inner::E26000); /// 27000 - pub const TRIGGERED_DATA_CHANGE_VIOLATION: SqlState = SqlState(Cow::Borrowed("27000")); + pub const TRIGGERED_DATA_CHANGE_VIOLATION: SqlState = SqlState(Inner::E27000); /// 28000 - pub const INVALID_AUTHORIZATION_SPECIFICATION: SqlState = SqlState(Cow::Borrowed("28000")); + pub const INVALID_AUTHORIZATION_SPECIFICATION: SqlState = SqlState(Inner::E28000); /// 28P01 - pub const INVALID_PASSWORD: SqlState = SqlState(Cow::Borrowed("28P01")); + pub const INVALID_PASSWORD: SqlState = SqlState(Inner::E28P01); /// 2B000 - pub const DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST: SqlState = - SqlState(Cow::Borrowed("2B000")); + pub const DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST: SqlState = SqlState(Inner::E2B000); /// 2BP01 - pub const DEPENDENT_OBJECTS_STILL_EXIST: SqlState = SqlState(Cow::Borrowed("2BP01")); + pub const DEPENDENT_OBJECTS_STILL_EXIST: SqlState = SqlState(Inner::E2BP01); /// 2D000 - pub const INVALID_TRANSACTION_TERMINATION: SqlState = SqlState(Cow::Borrowed("2D000")); + pub const INVALID_TRANSACTION_TERMINATION: SqlState = SqlState(Inner::E2D000); /// 2F000 - pub const SQL_ROUTINE_EXCEPTION: SqlState = SqlState(Cow::Borrowed("2F000")); + pub const SQL_ROUTINE_EXCEPTION: SqlState = SqlState(Inner::E2F000); /// 2F005 - pub const S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT: SqlState = - SqlState(Cow::Borrowed("2F005")); + pub const S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT: SqlState = SqlState(Inner::E2F005); /// 2F002 - pub const S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED: SqlState = SqlState(Cow::Borrowed("2F002")); + pub const S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED: SqlState = SqlState(Inner::E2F002); /// 2F003 - pub const S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED: SqlState = SqlState(Cow::Borrowed("2F003")); + pub const S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED: SqlState = SqlState(Inner::E2F003); /// 2F004 - pub const S_R_E_READING_SQL_DATA_NOT_PERMITTED: SqlState = SqlState(Cow::Borrowed("2F004")); + pub const S_R_E_READING_SQL_DATA_NOT_PERMITTED: SqlState = SqlState(Inner::E2F004); /// 34000 - pub const INVALID_CURSOR_NAME: SqlState = SqlState(Cow::Borrowed("34000")); + pub const INVALID_CURSOR_NAME: SqlState = SqlState(Inner::E34000); /// 34000 - pub const UNDEFINED_CURSOR: SqlState = SqlState(Cow::Borrowed("34000")); + pub const UNDEFINED_CURSOR: SqlState = SqlState(Inner::E34000); /// 38000 - pub const EXTERNAL_ROUTINE_EXCEPTION: SqlState = SqlState(Cow::Borrowed("38000")); + pub const EXTERNAL_ROUTINE_EXCEPTION: SqlState = SqlState(Inner::E38000); /// 38001 - pub const E_R_E_CONTAINING_SQL_NOT_PERMITTED: SqlState = SqlState(Cow::Borrowed("38001")); + pub const E_R_E_CONTAINING_SQL_NOT_PERMITTED: SqlState = SqlState(Inner::E38001); /// 38002 - pub const E_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED: SqlState = SqlState(Cow::Borrowed("38002")); + pub const E_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED: SqlState = SqlState(Inner::E38002); /// 38003 - pub const E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED: SqlState = SqlState(Cow::Borrowed("38003")); + pub const E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED: SqlState = SqlState(Inner::E38003); /// 38004 - pub const E_R_E_READING_SQL_DATA_NOT_PERMITTED: SqlState = SqlState(Cow::Borrowed("38004")); + pub const E_R_E_READING_SQL_DATA_NOT_PERMITTED: SqlState = SqlState(Inner::E38004); /// 39000 - pub const EXTERNAL_ROUTINE_INVOCATION_EXCEPTION: SqlState = SqlState(Cow::Borrowed("39000")); + pub const EXTERNAL_ROUTINE_INVOCATION_EXCEPTION: SqlState = SqlState(Inner::E39000); /// 39001 - pub const E_R_I_E_INVALID_SQLSTATE_RETURNED: SqlState = SqlState(Cow::Borrowed("39001")); + pub const E_R_I_E_INVALID_SQLSTATE_RETURNED: SqlState = SqlState(Inner::E39001); /// 39004 - pub const E_R_I_E_NULL_VALUE_NOT_ALLOWED: SqlState = SqlState(Cow::Borrowed("39004")); + pub const E_R_I_E_NULL_VALUE_NOT_ALLOWED: SqlState = SqlState(Inner::E39004); /// 39P01 - pub const E_R_I_E_TRIGGER_PROTOCOL_VIOLATED: SqlState = SqlState(Cow::Borrowed("39P01")); + pub const E_R_I_E_TRIGGER_PROTOCOL_VIOLATED: SqlState = SqlState(Inner::E39P01); /// 39P02 - pub const E_R_I_E_SRF_PROTOCOL_VIOLATED: SqlState = SqlState(Cow::Borrowed("39P02")); + pub const E_R_I_E_SRF_PROTOCOL_VIOLATED: SqlState = SqlState(Inner::E39P02); /// 39P03 - pub const E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED: SqlState = SqlState(Cow::Borrowed("39P03")); + pub const E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED: SqlState = SqlState(Inner::E39P03); /// 3B000 - pub const SAVEPOINT_EXCEPTION: SqlState = SqlState(Cow::Borrowed("3B000")); + pub const SAVEPOINT_EXCEPTION: SqlState = SqlState(Inner::E3B000); /// 3B001 - pub const S_E_INVALID_SPECIFICATION: SqlState = SqlState(Cow::Borrowed("3B001")); + pub const S_E_INVALID_SPECIFICATION: SqlState = SqlState(Inner::E3B001); /// 3D000 - pub const INVALID_CATALOG_NAME: SqlState = SqlState(Cow::Borrowed("3D000")); + pub const INVALID_CATALOG_NAME: SqlState = SqlState(Inner::E3D000); /// 3D000 - pub const UNDEFINED_DATABASE: SqlState = SqlState(Cow::Borrowed("3D000")); + pub const UNDEFINED_DATABASE: SqlState = SqlState(Inner::E3D000); /// 3F000 - pub const INVALID_SCHEMA_NAME: SqlState = SqlState(Cow::Borrowed("3F000")); + pub const INVALID_SCHEMA_NAME: SqlState = SqlState(Inner::E3F000); /// 3F000 - pub const UNDEFINED_SCHEMA: SqlState = SqlState(Cow::Borrowed("3F000")); + pub const UNDEFINED_SCHEMA: SqlState = SqlState(Inner::E3F000); /// 40000 - pub const TRANSACTION_ROLLBACK: SqlState = SqlState(Cow::Borrowed("40000")); + pub const TRANSACTION_ROLLBACK: SqlState = SqlState(Inner::E40000); /// 40002 - pub const T_R_INTEGRITY_CONSTRAINT_VIOLATION: SqlState = SqlState(Cow::Borrowed("40002")); + pub const T_R_INTEGRITY_CONSTRAINT_VIOLATION: SqlState = SqlState(Inner::E40002); /// 40001 - pub const T_R_SERIALIZATION_FAILURE: SqlState = SqlState(Cow::Borrowed("40001")); + pub const T_R_SERIALIZATION_FAILURE: SqlState = SqlState(Inner::E40001); /// 40003 - pub const T_R_STATEMENT_COMPLETION_UNKNOWN: SqlState = SqlState(Cow::Borrowed("40003")); + pub const T_R_STATEMENT_COMPLETION_UNKNOWN: SqlState = SqlState(Inner::E40003); /// 40P01 - pub const T_R_DEADLOCK_DETECTED: SqlState = SqlState(Cow::Borrowed("40P01")); + pub const T_R_DEADLOCK_DETECTED: SqlState = SqlState(Inner::E40P01); /// 42000 - pub const SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION: SqlState = SqlState(Cow::Borrowed("42000")); + pub const SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION: SqlState = SqlState(Inner::E42000); /// 42601 - pub const SYNTAX_ERROR: SqlState = SqlState(Cow::Borrowed("42601")); + pub const SYNTAX_ERROR: SqlState = SqlState(Inner::E42601); /// 42501 - pub const INSUFFICIENT_PRIVILEGE: SqlState = SqlState(Cow::Borrowed("42501")); + pub const INSUFFICIENT_PRIVILEGE: SqlState = SqlState(Inner::E42501); /// 42846 - pub const CANNOT_COERCE: SqlState = SqlState(Cow::Borrowed("42846")); + pub const CANNOT_COERCE: SqlState = SqlState(Inner::E42846); /// 42803 - pub const GROUPING_ERROR: SqlState = SqlState(Cow::Borrowed("42803")); + pub const GROUPING_ERROR: SqlState = SqlState(Inner::E42803); /// 42P20 - pub const WINDOWING_ERROR: SqlState = SqlState(Cow::Borrowed("42P20")); + pub const WINDOWING_ERROR: SqlState = SqlState(Inner::E42P20); /// 42P19 - pub const INVALID_RECURSION: SqlState = SqlState(Cow::Borrowed("42P19")); + pub const INVALID_RECURSION: SqlState = SqlState(Inner::E42P19); /// 42830 - pub const INVALID_FOREIGN_KEY: SqlState = SqlState(Cow::Borrowed("42830")); + pub const INVALID_FOREIGN_KEY: SqlState = SqlState(Inner::E42830); /// 42602 - pub const INVALID_NAME: SqlState = SqlState(Cow::Borrowed("42602")); + pub const INVALID_NAME: SqlState = SqlState(Inner::E42602); /// 42622 - pub const NAME_TOO_LONG: SqlState = SqlState(Cow::Borrowed("42622")); + pub const NAME_TOO_LONG: SqlState = SqlState(Inner::E42622); /// 42939 - pub const RESERVED_NAME: SqlState = SqlState(Cow::Borrowed("42939")); + pub const RESERVED_NAME: SqlState = SqlState(Inner::E42939); /// 42804 - pub const DATATYPE_MISMATCH: SqlState = SqlState(Cow::Borrowed("42804")); + pub const DATATYPE_MISMATCH: SqlState = SqlState(Inner::E42804); /// 42P18 - pub const INDETERMINATE_DATATYPE: SqlState = SqlState(Cow::Borrowed("42P18")); + pub const INDETERMINATE_DATATYPE: SqlState = SqlState(Inner::E42P18); /// 42P21 - pub const COLLATION_MISMATCH: SqlState = SqlState(Cow::Borrowed("42P21")); + pub const COLLATION_MISMATCH: SqlState = SqlState(Inner::E42P21); /// 42P22 - pub const INDETERMINATE_COLLATION: SqlState = SqlState(Cow::Borrowed("42P22")); + pub const INDETERMINATE_COLLATION: SqlState = SqlState(Inner::E42P22); /// 42809 - pub const WRONG_OBJECT_TYPE: SqlState = SqlState(Cow::Borrowed("42809")); + pub const WRONG_OBJECT_TYPE: SqlState = SqlState(Inner::E42809); /// 428C9 - pub const GENERATED_ALWAYS: SqlState = SqlState(Cow::Borrowed("428C9")); + pub const GENERATED_ALWAYS: SqlState = SqlState(Inner::E428C9); /// 42703 - pub const UNDEFINED_COLUMN: SqlState = SqlState(Cow::Borrowed("42703")); + pub const UNDEFINED_COLUMN: SqlState = SqlState(Inner::E42703); /// 42883 - pub const UNDEFINED_FUNCTION: SqlState = SqlState(Cow::Borrowed("42883")); + pub const UNDEFINED_FUNCTION: SqlState = SqlState(Inner::E42883); /// 42P01 - pub const UNDEFINED_TABLE: SqlState = SqlState(Cow::Borrowed("42P01")); + pub const UNDEFINED_TABLE: SqlState = SqlState(Inner::E42P01); /// 42P02 - pub const UNDEFINED_PARAMETER: SqlState = SqlState(Cow::Borrowed("42P02")); + pub const UNDEFINED_PARAMETER: SqlState = SqlState(Inner::E42P02); /// 42704 - pub const UNDEFINED_OBJECT: SqlState = SqlState(Cow::Borrowed("42704")); + pub const UNDEFINED_OBJECT: SqlState = SqlState(Inner::E42704); /// 42701 - pub const DUPLICATE_COLUMN: SqlState = SqlState(Cow::Borrowed("42701")); + pub const DUPLICATE_COLUMN: SqlState = SqlState(Inner::E42701); /// 42P03 - pub const DUPLICATE_CURSOR: SqlState = SqlState(Cow::Borrowed("42P03")); + pub const DUPLICATE_CURSOR: SqlState = SqlState(Inner::E42P03); /// 42P04 - pub const DUPLICATE_DATABASE: SqlState = SqlState(Cow::Borrowed("42P04")); + pub const DUPLICATE_DATABASE: SqlState = SqlState(Inner::E42P04); /// 42723 - pub const DUPLICATE_FUNCTION: SqlState = SqlState(Cow::Borrowed("42723")); + pub const DUPLICATE_FUNCTION: SqlState = SqlState(Inner::E42723); /// 42P05 - pub const DUPLICATE_PSTATEMENT: SqlState = SqlState(Cow::Borrowed("42P05")); + pub const DUPLICATE_PSTATEMENT: SqlState = SqlState(Inner::E42P05); /// 42P06 - pub const DUPLICATE_SCHEMA: SqlState = SqlState(Cow::Borrowed("42P06")); + pub const DUPLICATE_SCHEMA: SqlState = SqlState(Inner::E42P06); /// 42P07 - pub const DUPLICATE_TABLE: SqlState = SqlState(Cow::Borrowed("42P07")); + pub const DUPLICATE_TABLE: SqlState = SqlState(Inner::E42P07); /// 42712 - pub const DUPLICATE_ALIAS: SqlState = SqlState(Cow::Borrowed("42712")); + pub const DUPLICATE_ALIAS: SqlState = SqlState(Inner::E42712); /// 42710 - pub const DUPLICATE_OBJECT: SqlState = SqlState(Cow::Borrowed("42710")); + pub const DUPLICATE_OBJECT: SqlState = SqlState(Inner::E42710); /// 42702 - pub const AMBIGUOUS_COLUMN: SqlState = SqlState(Cow::Borrowed("42702")); + pub const AMBIGUOUS_COLUMN: SqlState = SqlState(Inner::E42702); /// 42725 - pub const AMBIGUOUS_FUNCTION: SqlState = SqlState(Cow::Borrowed("42725")); + pub const AMBIGUOUS_FUNCTION: SqlState = SqlState(Inner::E42725); /// 42P08 - pub const AMBIGUOUS_PARAMETER: SqlState = SqlState(Cow::Borrowed("42P08")); + pub const AMBIGUOUS_PARAMETER: SqlState = SqlState(Inner::E42P08); /// 42P09 - pub const AMBIGUOUS_ALIAS: SqlState = SqlState(Cow::Borrowed("42P09")); + pub const AMBIGUOUS_ALIAS: SqlState = SqlState(Inner::E42P09); /// 42P10 - pub const INVALID_COLUMN_REFERENCE: SqlState = SqlState(Cow::Borrowed("42P10")); + pub const INVALID_COLUMN_REFERENCE: SqlState = SqlState(Inner::E42P10); /// 42611 - pub const INVALID_COLUMN_DEFINITION: SqlState = SqlState(Cow::Borrowed("42611")); + pub const INVALID_COLUMN_DEFINITION: SqlState = SqlState(Inner::E42611); /// 42P11 - pub const INVALID_CURSOR_DEFINITION: SqlState = SqlState(Cow::Borrowed("42P11")); + pub const INVALID_CURSOR_DEFINITION: SqlState = SqlState(Inner::E42P11); /// 42P12 - pub const INVALID_DATABASE_DEFINITION: SqlState = SqlState(Cow::Borrowed("42P12")); + pub const INVALID_DATABASE_DEFINITION: SqlState = SqlState(Inner::E42P12); /// 42P13 - pub const INVALID_FUNCTION_DEFINITION: SqlState = SqlState(Cow::Borrowed("42P13")); + pub const INVALID_FUNCTION_DEFINITION: SqlState = SqlState(Inner::E42P13); /// 42P14 - pub const INVALID_PSTATEMENT_DEFINITION: SqlState = SqlState(Cow::Borrowed("42P14")); + pub const INVALID_PSTATEMENT_DEFINITION: SqlState = SqlState(Inner::E42P14); /// 42P15 - pub const INVALID_SCHEMA_DEFINITION: SqlState = SqlState(Cow::Borrowed("42P15")); + pub const INVALID_SCHEMA_DEFINITION: SqlState = SqlState(Inner::E42P15); /// 42P16 - pub const INVALID_TABLE_DEFINITION: SqlState = SqlState(Cow::Borrowed("42P16")); + pub const INVALID_TABLE_DEFINITION: SqlState = SqlState(Inner::E42P16); /// 42P17 - pub const INVALID_OBJECT_DEFINITION: SqlState = SqlState(Cow::Borrowed("42P17")); + pub const INVALID_OBJECT_DEFINITION: SqlState = SqlState(Inner::E42P17); /// 44000 - pub const WITH_CHECK_OPTION_VIOLATION: SqlState = SqlState(Cow::Borrowed("44000")); + pub const WITH_CHECK_OPTION_VIOLATION: SqlState = SqlState(Inner::E44000); /// 53000 - pub const INSUFFICIENT_RESOURCES: SqlState = SqlState(Cow::Borrowed("53000")); + pub const INSUFFICIENT_RESOURCES: SqlState = SqlState(Inner::E53000); /// 53100 - pub const DISK_FULL: SqlState = SqlState(Cow::Borrowed("53100")); + pub const DISK_FULL: SqlState = SqlState(Inner::E53100); /// 53200 - pub const OUT_OF_MEMORY: SqlState = SqlState(Cow::Borrowed("53200")); + pub const OUT_OF_MEMORY: SqlState = SqlState(Inner::E53200); /// 53300 - pub const TOO_MANY_CONNECTIONS: SqlState = SqlState(Cow::Borrowed("53300")); + pub const TOO_MANY_CONNECTIONS: SqlState = SqlState(Inner::E53300); /// 53400 - pub const CONFIGURATION_LIMIT_EXCEEDED: SqlState = SqlState(Cow::Borrowed("53400")); + pub const CONFIGURATION_LIMIT_EXCEEDED: SqlState = SqlState(Inner::E53400); /// 54000 - pub const PROGRAM_LIMIT_EXCEEDED: SqlState = SqlState(Cow::Borrowed("54000")); + pub const PROGRAM_LIMIT_EXCEEDED: SqlState = SqlState(Inner::E54000); /// 54001 - pub const STATEMENT_TOO_COMPLEX: SqlState = SqlState(Cow::Borrowed("54001")); + pub const STATEMENT_TOO_COMPLEX: SqlState = SqlState(Inner::E54001); /// 54011 - pub const TOO_MANY_COLUMNS: SqlState = SqlState(Cow::Borrowed("54011")); + pub const TOO_MANY_COLUMNS: SqlState = SqlState(Inner::E54011); /// 54023 - pub const TOO_MANY_ARGUMENTS: SqlState = SqlState(Cow::Borrowed("54023")); + pub const TOO_MANY_ARGUMENTS: SqlState = SqlState(Inner::E54023); /// 55000 - pub const OBJECT_NOT_IN_PREREQUISITE_STATE: SqlState = SqlState(Cow::Borrowed("55000")); + pub const OBJECT_NOT_IN_PREREQUISITE_STATE: SqlState = SqlState(Inner::E55000); /// 55006 - pub const OBJECT_IN_USE: SqlState = SqlState(Cow::Borrowed("55006")); + pub const OBJECT_IN_USE: SqlState = SqlState(Inner::E55006); /// 55P02 - pub const CANT_CHANGE_RUNTIME_PARAM: SqlState = SqlState(Cow::Borrowed("55P02")); + pub const CANT_CHANGE_RUNTIME_PARAM: SqlState = SqlState(Inner::E55P02); /// 55P03 - pub const LOCK_NOT_AVAILABLE: SqlState = SqlState(Cow::Borrowed("55P03")); + pub const LOCK_NOT_AVAILABLE: SqlState = SqlState(Inner::E55P03); /// 55P04 - pub const UNSAFE_NEW_ENUM_VALUE_USAGE: SqlState = SqlState(Cow::Borrowed("55P04")); + pub const UNSAFE_NEW_ENUM_VALUE_USAGE: SqlState = SqlState(Inner::E55P04); /// 57000 - pub const OPERATOR_INTERVENTION: SqlState = SqlState(Cow::Borrowed("57000")); + pub const OPERATOR_INTERVENTION: SqlState = SqlState(Inner::E57000); /// 57014 - pub const QUERY_CANCELED: SqlState = SqlState(Cow::Borrowed("57014")); + pub const QUERY_CANCELED: SqlState = SqlState(Inner::E57014); /// 57P01 - pub const ADMIN_SHUTDOWN: SqlState = SqlState(Cow::Borrowed("57P01")); + pub const ADMIN_SHUTDOWN: SqlState = SqlState(Inner::E57P01); /// 57P02 - pub const CRASH_SHUTDOWN: SqlState = SqlState(Cow::Borrowed("57P02")); + pub const CRASH_SHUTDOWN: SqlState = SqlState(Inner::E57P02); /// 57P03 - pub const CANNOT_CONNECT_NOW: SqlState = SqlState(Cow::Borrowed("57P03")); + pub const CANNOT_CONNECT_NOW: SqlState = SqlState(Inner::E57P03); /// 57P04 - pub const DATABASE_DROPPED: SqlState = SqlState(Cow::Borrowed("57P04")); + pub const DATABASE_DROPPED: SqlState = SqlState(Inner::E57P04); /// 58000 - pub const SYSTEM_ERROR: SqlState = SqlState(Cow::Borrowed("58000")); + pub const SYSTEM_ERROR: SqlState = SqlState(Inner::E58000); /// 58030 - pub const IO_ERROR: SqlState = SqlState(Cow::Borrowed("58030")); + pub const IO_ERROR: SqlState = SqlState(Inner::E58030); /// 58P01 - pub const UNDEFINED_FILE: SqlState = SqlState(Cow::Borrowed("58P01")); + pub const UNDEFINED_FILE: SqlState = SqlState(Inner::E58P01); /// 58P02 - pub const DUPLICATE_FILE: SqlState = SqlState(Cow::Borrowed("58P02")); + pub const DUPLICATE_FILE: SqlState = SqlState(Inner::E58P02); /// 72000 - pub const SNAPSHOT_TOO_OLD: SqlState = SqlState(Cow::Borrowed("72000")); + pub const SNAPSHOT_TOO_OLD: SqlState = SqlState(Inner::E72000); /// F0000 - pub const CONFIG_FILE_ERROR: SqlState = SqlState(Cow::Borrowed("F0000")); + pub const CONFIG_FILE_ERROR: SqlState = SqlState(Inner::EF0000); /// F0001 - pub const LOCK_FILE_EXISTS: SqlState = SqlState(Cow::Borrowed("F0001")); + pub const LOCK_FILE_EXISTS: SqlState = SqlState(Inner::EF0001); /// HV000 - pub const FDW_ERROR: SqlState = SqlState(Cow::Borrowed("HV000")); + pub const FDW_ERROR: SqlState = SqlState(Inner::EHV000); /// HV005 - pub const FDW_COLUMN_NAME_NOT_FOUND: SqlState = SqlState(Cow::Borrowed("HV005")); + pub const FDW_COLUMN_NAME_NOT_FOUND: SqlState = SqlState(Inner::EHV005); /// HV002 - pub const FDW_DYNAMIC_PARAMETER_VALUE_NEEDED: SqlState = SqlState(Cow::Borrowed("HV002")); + pub const FDW_DYNAMIC_PARAMETER_VALUE_NEEDED: SqlState = SqlState(Inner::EHV002); /// HV010 - pub const FDW_FUNCTION_SEQUENCE_ERROR: SqlState = SqlState(Cow::Borrowed("HV010")); + pub const FDW_FUNCTION_SEQUENCE_ERROR: SqlState = SqlState(Inner::EHV010); /// HV021 - pub const FDW_INCONSISTENT_DESCRIPTOR_INFORMATION: SqlState = SqlState(Cow::Borrowed("HV021")); + pub const FDW_INCONSISTENT_DESCRIPTOR_INFORMATION: SqlState = SqlState(Inner::EHV021); /// HV024 - pub const FDW_INVALID_ATTRIBUTE_VALUE: SqlState = SqlState(Cow::Borrowed("HV024")); + pub const FDW_INVALID_ATTRIBUTE_VALUE: SqlState = SqlState(Inner::EHV024); /// HV007 - pub const FDW_INVALID_COLUMN_NAME: SqlState = SqlState(Cow::Borrowed("HV007")); + pub const FDW_INVALID_COLUMN_NAME: SqlState = SqlState(Inner::EHV007); /// HV008 - pub const FDW_INVALID_COLUMN_NUMBER: SqlState = SqlState(Cow::Borrowed("HV008")); + pub const FDW_INVALID_COLUMN_NUMBER: SqlState = SqlState(Inner::EHV008); /// HV004 - pub const FDW_INVALID_DATA_TYPE: SqlState = SqlState(Cow::Borrowed("HV004")); + pub const FDW_INVALID_DATA_TYPE: SqlState = SqlState(Inner::EHV004); /// HV006 - pub const FDW_INVALID_DATA_TYPE_DESCRIPTORS: SqlState = SqlState(Cow::Borrowed("HV006")); + pub const FDW_INVALID_DATA_TYPE_DESCRIPTORS: SqlState = SqlState(Inner::EHV006); /// HV091 - pub const FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER: SqlState = SqlState(Cow::Borrowed("HV091")); + pub const FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER: SqlState = SqlState(Inner::EHV091); /// HV00B - pub const FDW_INVALID_HANDLE: SqlState = SqlState(Cow::Borrowed("HV00B")); + pub const FDW_INVALID_HANDLE: SqlState = SqlState(Inner::EHV00B); /// HV00C - pub const FDW_INVALID_OPTION_INDEX: SqlState = SqlState(Cow::Borrowed("HV00C")); + pub const FDW_INVALID_OPTION_INDEX: SqlState = SqlState(Inner::EHV00C); /// HV00D - pub const FDW_INVALID_OPTION_NAME: SqlState = SqlState(Cow::Borrowed("HV00D")); + pub const FDW_INVALID_OPTION_NAME: SqlState = SqlState(Inner::EHV00D); /// HV090 - pub const FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH: SqlState = - SqlState(Cow::Borrowed("HV090")); + pub const FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH: SqlState = SqlState(Inner::EHV090); /// HV00A - pub const FDW_INVALID_STRING_FORMAT: SqlState = SqlState(Cow::Borrowed("HV00A")); + pub const FDW_INVALID_STRING_FORMAT: SqlState = SqlState(Inner::EHV00A); /// HV009 - pub const FDW_INVALID_USE_OF_NULL_POINTER: SqlState = SqlState(Cow::Borrowed("HV009")); + pub const FDW_INVALID_USE_OF_NULL_POINTER: SqlState = SqlState(Inner::EHV009); /// HV014 - pub const FDW_TOO_MANY_HANDLES: SqlState = SqlState(Cow::Borrowed("HV014")); + pub const FDW_TOO_MANY_HANDLES: SqlState = SqlState(Inner::EHV014); /// HV001 - pub const FDW_OUT_OF_MEMORY: SqlState = SqlState(Cow::Borrowed("HV001")); + pub const FDW_OUT_OF_MEMORY: SqlState = SqlState(Inner::EHV001); /// HV00P - pub const FDW_NO_SCHEMAS: SqlState = SqlState(Cow::Borrowed("HV00P")); + pub const FDW_NO_SCHEMAS: SqlState = SqlState(Inner::EHV00P); /// HV00J - pub const FDW_OPTION_NAME_NOT_FOUND: SqlState = SqlState(Cow::Borrowed("HV00J")); + pub const FDW_OPTION_NAME_NOT_FOUND: SqlState = SqlState(Inner::EHV00J); /// HV00K - pub const FDW_REPLY_HANDLE: SqlState = SqlState(Cow::Borrowed("HV00K")); + pub const FDW_REPLY_HANDLE: SqlState = SqlState(Inner::EHV00K); /// HV00Q - pub const FDW_SCHEMA_NOT_FOUND: SqlState = SqlState(Cow::Borrowed("HV00Q")); + pub const FDW_SCHEMA_NOT_FOUND: SqlState = SqlState(Inner::EHV00Q); /// HV00R - pub const FDW_TABLE_NOT_FOUND: SqlState = SqlState(Cow::Borrowed("HV00R")); + pub const FDW_TABLE_NOT_FOUND: SqlState = SqlState(Inner::EHV00R); /// HV00L - pub const FDW_UNABLE_TO_CREATE_EXECUTION: SqlState = SqlState(Cow::Borrowed("HV00L")); + pub const FDW_UNABLE_TO_CREATE_EXECUTION: SqlState = SqlState(Inner::EHV00L); /// HV00M - pub const FDW_UNABLE_TO_CREATE_REPLY: SqlState = SqlState(Cow::Borrowed("HV00M")); + pub const FDW_UNABLE_TO_CREATE_REPLY: SqlState = SqlState(Inner::EHV00M); /// HV00N - pub const FDW_UNABLE_TO_ESTABLISH_CONNECTION: SqlState = SqlState(Cow::Borrowed("HV00N")); + pub const FDW_UNABLE_TO_ESTABLISH_CONNECTION: SqlState = SqlState(Inner::EHV00N); /// P0000 - pub const PLPGSQL_ERROR: SqlState = SqlState(Cow::Borrowed("P0000")); + pub const PLPGSQL_ERROR: SqlState = SqlState(Inner::EP0000); /// P0001 - pub const RAISE_EXCEPTION: SqlState = SqlState(Cow::Borrowed("P0001")); + pub const RAISE_EXCEPTION: SqlState = SqlState(Inner::EP0001); /// P0002 - pub const NO_DATA_FOUND: SqlState = SqlState(Cow::Borrowed("P0002")); + pub const NO_DATA_FOUND: SqlState = SqlState(Inner::EP0002); /// P0003 - pub const TOO_MANY_ROWS: SqlState = SqlState(Cow::Borrowed("P0003")); + pub const TOO_MANY_ROWS: SqlState = SqlState(Inner::EP0003); /// P0004 - pub const ASSERT_FAILURE: SqlState = SqlState(Cow::Borrowed("P0004")); + pub const ASSERT_FAILURE: SqlState = SqlState(Inner::EP0004); /// XX000 - pub const INTERNAL_ERROR: SqlState = SqlState(Cow::Borrowed("XX000")); + pub const INTERNAL_ERROR: SqlState = SqlState(Inner::EXX000); /// XX001 - pub const DATA_CORRUPTED: SqlState = SqlState(Cow::Borrowed("XX001")); + pub const DATA_CORRUPTED: SqlState = SqlState(Inner::EXX001); /// XX002 - pub const INDEX_CORRUPTED: SqlState = SqlState(Cow::Borrowed("XX002")); + pub const INDEX_CORRUPTED: SqlState = SqlState(Inner::EXX002); } + +#[derive(PartialEq, Eq, Clone, Debug)] +enum Inner { + E00000, + E01000, + E0100C, + E01008, + E01003, + E01007, + E01006, + E01004, + E01P01, + E02000, + E02001, + E03000, + E08000, + E08003, + E08006, + E08001, + E08004, + E08007, + E08P01, + E09000, + E0A000, + E0B000, + E0F000, + E0F001, + E0L000, + E0LP01, + E0P000, + E0Z000, + E0Z002, + E20000, + E21000, + E22000, + E2202E, + E22021, + E22008, + E22012, + E22005, + E2200B, + E22022, + E22015, + E2201E, + E22014, + E22016, + E2201F, + E2201G, + E22018, + E22007, + E22019, + E2200D, + E22025, + E22P06, + E22010, + E22023, + E22013, + E2201B, + E2201W, + E2201X, + E2202H, + E2202G, + E22009, + E2200C, + E2200G, + E22004, + E22002, + E22003, + E2200H, + E22026, + E22001, + E22011, + E22027, + E22024, + E2200F, + E22P01, + E22P02, + E22P03, + E22P04, + E22P05, + E2200L, + E2200M, + E2200N, + E2200S, + E2200T, + E22030, + E22031, + E22032, + E22033, + E22034, + E22035, + E22036, + E22037, + E22038, + E22039, + E2203A, + E2203B, + E2203C, + E2203D, + E2203E, + E2203F, + E23000, + E23001, + E23502, + E23503, + E23505, + E23514, + E23P01, + E24000, + E25000, + E25001, + E25002, + E25008, + E25003, + E25004, + E25005, + E25006, + E25007, + E25P01, + E25P02, + E25P03, + E26000, + E27000, + E28000, + E28P01, + E2B000, + E2BP01, + E2D000, + E2F000, + E2F005, + E2F002, + E2F003, + E2F004, + E34000, + E38000, + E38001, + E38002, + E38003, + E38004, + E39000, + E39001, + E39004, + E39P01, + E39P02, + E39P03, + E3B000, + E3B001, + E3D000, + E3F000, + E40000, + E40002, + E40001, + E40003, + E40P01, + E42000, + E42601, + E42501, + E42846, + E42803, + E42P20, + E42P19, + E42830, + E42602, + E42622, + E42939, + E42804, + E42P18, + E42P21, + E42P22, + E42809, + E428C9, + E42703, + E42883, + E42P01, + E42P02, + E42704, + E42701, + E42P03, + E42P04, + E42723, + E42P05, + E42P06, + E42P07, + E42712, + E42710, + E42702, + E42725, + E42P08, + E42P09, + E42P10, + E42611, + E42P11, + E42P12, + E42P13, + E42P14, + E42P15, + E42P16, + E42P17, + E44000, + E53000, + E53100, + E53200, + E53300, + E53400, + E54000, + E54001, + E54011, + E54023, + E55000, + E55006, + E55P02, + E55P03, + E55P04, + E57000, + E57014, + E57P01, + E57P02, + E57P03, + E57P04, + E58000, + E58030, + E58P01, + E58P02, + E72000, + EF0000, + EF0001, + EHV000, + EHV005, + EHV002, + EHV010, + EHV021, + EHV024, + EHV007, + EHV008, + EHV004, + EHV006, + EHV091, + EHV00B, + EHV00C, + EHV00D, + EHV090, + EHV00A, + EHV009, + EHV014, + EHV001, + EHV00P, + EHV00J, + EHV00K, + EHV00Q, + EHV00R, + EHV00L, + EHV00M, + EHV00N, + EP0000, + EP0001, + EP0002, + EP0003, + EP0004, + EXX000, + EXX001, + EXX002, + Other(Box), +} + #[rustfmt::skip] static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ::phf::Map { From 91ce9cdeec624511f79b39debfcf12bdac62178e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 24 Apr 2021 10:34:51 -0400 Subject: [PATCH 105/420] fix clippy --- codegen/src/sqlstate.rs | 1 + tokio-postgres/src/error/sqlstate.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/codegen/src/sqlstate.rs b/codegen/src/sqlstate.rs index ea3045654..d21b92eec 100644 --- a/codegen/src/sqlstate.rs +++ b/codegen/src/sqlstate.rs @@ -113,6 +113,7 @@ fn make_inner(codes: &LinkedHashMap>, file: &mut BufWriter Date: Sun, 25 Apr 2021 10:52:25 -0400 Subject: [PATCH 106/420] Release v0.7.2 --- tokio-postgres/CHANGELOG.md | 8 +++++++- tokio-postgres/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 7cc6c7071..3a7aa2ae7 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,6 +1,12 @@ # Change Log -## v0.7.1 - 2020-04-03 +## v0.7.2 - 2021-04-25 + +### Fixed + +* `SqlState` constants can now be used in `match` patterns. + +## v0.7.1 - 2021-04-03 ### Added diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index b1d093d4b..780c31963 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.7.1" +version = "0.7.2" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From 20f0d76459a20b934c9863c7638bd94f4fee506f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 29 Apr 2021 20:58:01 +0000 Subject: [PATCH 107/420] Upgrade to GitHub-native Dependabot --- .github/dependabot.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..a64a91b02 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: +- package-ecosystem: cargo + directory: "/" + schedule: + interval: daily + time: "13:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: socket2 + versions: + - 0.4.0 From 0f0de8c34d3858e188079060b75dd818ae469115 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 29 Apr 2021 17:00:22 -0400 Subject: [PATCH 108/420] Update dependabot.yml --- .github/dependabot.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index a64a91b02..1332f8eb5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,7 +6,3 @@ updates: interval: daily time: "13:00" open-pull-requests-limit: 10 - ignore: - - dependency-name: socket2 - versions: - - 0.4.0 From 83616fadb5c0b88b34d1f83478ac6d46546d2b31 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Apr 2021 21:02:13 +0000 Subject: [PATCH 109/420] Update hmac requirement from 0.10 to 0.11 Updates the requirements on [hmac](https://github.com/RustCrypto/MACs) to permit the latest version. - [Release notes](https://github.com/RustCrypto/MACs/releases) - [Commits](https://github.com/RustCrypto/MACs/compare/hmac-v0.10.0...hmac-v0.11.0) Signed-off-by: dependabot[bot] --- 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 4fd288697..d4ae8c301 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -13,7 +13,7 @@ base64 = "0.13" byteorder = "1.0" bytes = "1.0" fallible-iterator = "0.2" -hmac = "0.10" +hmac = "0.11" md-5 = "0.9" memchr = "2.0" rand = "0.8" From 4e8b9078a194c6b65bdff6882a76b8361a53a02e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 29 Apr 2021 17:07:24 -0400 Subject: [PATCH 110/420] fix build --- postgres-protocol/src/authentication/sasl.rs | 17 +++++++++-------- postgres-protocol/src/password/mod.rs | 8 ++++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/postgres-protocol/src/authentication/sasl.rs b/postgres-protocol/src/authentication/sasl.rs index 7c0d1754f..a3704ce16 100644 --- a/postgres-protocol/src/authentication/sasl.rs +++ b/postgres-protocol/src/authentication/sasl.rs @@ -33,7 +33,8 @@ fn normalize(pass: &[u8]) -> Vec { } pub(crate) fn hi(str: &[u8], salt: &[u8], i: u32) -> [u8; 32] { - let mut hmac = Hmac::::new_varkey(str).expect("HMAC is able to accept all key sizes"); + let mut hmac = + Hmac::::new_from_slice(str).expect("HMAC is able to accept all key sizes"); hmac.update(salt); hmac.update(&[0, 0, 0, 1]); let mut prev = hmac.finalize().into_bytes(); @@ -41,7 +42,7 @@ pub(crate) fn hi(str: &[u8], salt: &[u8], i: u32) -> [u8; 32] { let mut hi = prev; for _ in 1..i { - let mut hmac = Hmac::::new_varkey(str).expect("already checked above"); + let mut hmac = Hmac::::new_from_slice(str).expect("already checked above"); hmac.update(&prev); prev = hmac.finalize().into_bytes(); @@ -195,7 +196,7 @@ impl ScramSha256 { let salted_password = hi(&password, &salt, parsed.iteration_count); - let mut hmac = Hmac::::new_varkey(&salted_password) + let mut hmac = Hmac::::new_from_slice(&salted_password) .expect("HMAC is able to accept all key sizes"); hmac.update(b"Client Key"); let client_key = hmac.finalize().into_bytes(); @@ -214,8 +215,8 @@ impl ScramSha256 { let auth_message = format!("n=,r={},{},{}", client_nonce, message, self.message); - let mut hmac = - Hmac::::new_varkey(&stored_key).expect("HMAC is able to accept all key sizes"); + let mut hmac = Hmac::::new_from_slice(&stored_key) + .expect("HMAC is able to accept all key sizes"); hmac.update(auth_message.as_bytes()); let client_signature = hmac.finalize().into_bytes(); @@ -266,13 +267,13 @@ impl ScramSha256 { Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidInput, e)), }; - let mut hmac = Hmac::::new_varkey(&salted_password) + let mut hmac = Hmac::::new_from_slice(&salted_password) .expect("HMAC is able to accept all key sizes"); hmac.update(b"Server Key"); let server_key = hmac.finalize().into_bytes(); - let mut hmac = - Hmac::::new_varkey(&server_key).expect("HMAC is able to accept all key sizes"); + let mut hmac = Hmac::::new_from_slice(&server_key) + .expect("HMAC is able to accept all key sizes"); hmac.update(auth_message.as_bytes()); hmac.verify(&verifier) .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "SCRAM verification error")) diff --git a/postgres-protocol/src/password/mod.rs b/postgres-protocol/src/password/mod.rs index ccb95c79b..1b32ae8f8 100644 --- a/postgres-protocol/src/password/mod.rs +++ b/postgres-protocol/src/password/mod.rs @@ -61,8 +61,8 @@ pub(crate) fn scram_sha_256_salt(password: &[u8], salt: [u8; SCRAM_DEFAULT_SALT_ let salted_password = sasl::hi(&prepared, &salt, SCRAM_DEFAULT_ITERATIONS); // client key - let mut hmac = - Hmac::::new_varkey(&salted_password).expect("HMAC is able to accept all key sizes"); + let mut hmac = Hmac::::new_from_slice(&salted_password) + .expect("HMAC is able to accept all key sizes"); hmac.update(b"Client Key"); let client_key = hmac.finalize().into_bytes(); @@ -72,8 +72,8 @@ pub(crate) fn scram_sha_256_salt(password: &[u8], salt: [u8; SCRAM_DEFAULT_SALT_ let stored_key = hash.finalize_fixed(); // server key - let mut hmac = - Hmac::::new_varkey(&salted_password).expect("HMAC is able to accept all key sizes"); + let mut hmac = Hmac::::new_from_slice(&salted_password) + .expect("HMAC is able to accept all key sizes"); hmac.update(b"Server Key"); let server_key = hmac.finalize().into_bytes(); From a84a45d88ed157c8756d5e54b2b13467721e5d12 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Fri, 14 May 2021 14:59:07 +0100 Subject: [PATCH 111/420] Fix deadlock when pipelining statements. When executing statements in parallel there is a race where we prepare the type info queries multiple times, and so insert into the type info caches multiple times. This resulted in any existing cached `Statement` to be dropped, running its destructor which attempts to take out the state lock that is already being held, resulting in a deadlock. Fixes #772. --- tokio-postgres/src/client.rs | 45 +++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index f19005e55..b417c1396 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -55,8 +55,17 @@ impl Responses { } struct State { + /// A cached prepared statement for basic information for a type from its + /// OID. Corresponds to [TYPEINFO_QUERY](prepare::TYPEINFO_QUERY) (or its + /// fallback). typeinfo: Option, + /// A cached prepared statement for getting information for a composite type + /// from its OID. Corresponds to + /// [TYPEINFO_QUERY](prepare::TYPEINFO_COMPOSITE_QUERY). typeinfo_composite: Option, + /// A cached prepared statement for getting information for a composite type + /// from its OID. Corresponds to + /// [TYPEINFO_QUERY](prepare::TYPEINFO_COMPOSITE_QUERY) (or its fallback). typeinfo_enum: Option, types: HashMap, buf: BytesMut, @@ -86,7 +95,17 @@ impl InnerClient { } pub fn set_typeinfo(&self, statement: &Statement) { - self.state.lock().typeinfo = Some(statement.clone()); + // We only insert the statement if there isn't already a cached + // statement (this is safe as they are prepared statements for the same + // query). + // + // Note: We need to be sure that we don't drop a Statement while holding + // the state lock as its drop handling will call `with_buf`, which tries + // to take the lock. + let mut state = self.state.lock(); + if state.typeinfo.is_none() { + state.typeinfo = Some(statement.clone()); + } } pub fn typeinfo_composite(&self) -> Option { @@ -94,7 +113,17 @@ impl InnerClient { } pub fn set_typeinfo_composite(&self, statement: &Statement) { - self.state.lock().typeinfo_composite = Some(statement.clone()); + // We only insert the statement if there isn't already a cached + // statement (this is safe as they are prepared statements for the same + // query). + // + // Note: We need to be sure that we don't drop a Statement while holding + // the state lock as its drop handling will call `with_buf`, which tries + // to take the lock. + let mut state = self.state.lock(); + if state.typeinfo_composite.is_none() { + state.typeinfo_composite = Some(statement.clone()); + } } pub fn typeinfo_enum(&self) -> Option { @@ -102,7 +131,17 @@ impl InnerClient { } pub fn set_typeinfo_enum(&self, statement: &Statement) { - self.state.lock().typeinfo_enum = Some(statement.clone()); + // We only insert the statement if there isn't already a cached + // statement (this is safe as they are prepared statements for the same + // query). + // + // Note: We need to be sure that we don't drop a Statement while holding + // the state lock as its drop handling will call `with_buf`, which tries + // to take the lock. + let mut state = self.state.lock(); + if state.typeinfo_enum.is_none() { + state.typeinfo_enum = Some(statement.clone()); + } } pub fn type_(&self, oid: Oid) -> Option { From b7215c60d9584a8fd4245cc85ccce8aba998637d Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Fri, 14 May 2021 15:20:36 +0100 Subject: [PATCH 112/420] Split State into two. There is no reason for the buffer and typeinfo caches to share the same lock. By splitting them it means we a) get slightly better performance, but more importantly b) it makes it harder to accidentally deadlock. --- tokio-postgres/src/client.rs | 81 +++++++++++++++++------------------- 1 file changed, 38 insertions(+), 43 deletions(-) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index b417c1396..4e8babf1d 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -54,26 +54,32 @@ impl Responses { } } -struct State { - /// A cached prepared statement for basic information for a type from its +/// A cache of type info and prepared statements for fetching type info +/// (corresponding to the queries in the [prepare](prepare) module). +#[derive(Default)] +struct CachedTypeInfo { + /// A statement for basic information for a type from its /// OID. Corresponds to [TYPEINFO_QUERY](prepare::TYPEINFO_QUERY) (or its /// fallback). typeinfo: Option, - /// A cached prepared statement for getting information for a composite type - /// from its OID. Corresponds to - /// [TYPEINFO_QUERY](prepare::TYPEINFO_COMPOSITE_QUERY). + /// A statement for getting information for a composite type from its OID. + /// Corresponds to [TYPEINFO_QUERY](prepare::TYPEINFO_COMPOSITE_QUERY). typeinfo_composite: Option, - /// A cached prepared statement for getting information for a composite type - /// from its OID. Corresponds to - /// [TYPEINFO_QUERY](prepare::TYPEINFO_COMPOSITE_QUERY) (or its fallback). + /// A statement for getting information for a composite type from its OID. + /// Corresponds to [TYPEINFO_QUERY](prepare::TYPEINFO_COMPOSITE_QUERY) (or + /// its fallback). typeinfo_enum: Option, + + /// Cache of types already looked up. types: HashMap, - buf: BytesMut, } pub struct InnerClient { sender: mpsc::UnboundedSender, - state: Mutex, + cached_typeinfo: Mutex, + + /// A buffer to use when writing out postgres commands. + buffer: Mutex, } impl InnerClient { @@ -91,7 +97,7 @@ impl InnerClient { } pub fn typeinfo(&self) -> Option { - self.state.lock().typeinfo.clone() + self.cached_typeinfo.lock().typeinfo.clone() } pub fn set_typeinfo(&self, statement: &Statement) { @@ -102,67 +108,61 @@ impl InnerClient { // Note: We need to be sure that we don't drop a Statement while holding // the state lock as its drop handling will call `with_buf`, which tries // to take the lock. - let mut state = self.state.lock(); - if state.typeinfo.is_none() { - state.typeinfo = Some(statement.clone()); + let mut cache = self.cached_typeinfo.lock(); + if cache.typeinfo.is_none() { + cache.typeinfo = Some(statement.clone()); } } pub fn typeinfo_composite(&self) -> Option { - self.state.lock().typeinfo_composite.clone() + self.cached_typeinfo.lock().typeinfo_composite.clone() } pub fn set_typeinfo_composite(&self, statement: &Statement) { // We only insert the statement if there isn't already a cached // statement (this is safe as they are prepared statements for the same // query). - // - // Note: We need to be sure that we don't drop a Statement while holding - // the state lock as its drop handling will call `with_buf`, which tries - // to take the lock. - let mut state = self.state.lock(); - if state.typeinfo_composite.is_none() { - state.typeinfo_composite = Some(statement.clone()); + let mut cache = self.cached_typeinfo.lock(); + if cache.typeinfo_composite.is_none() { + cache.typeinfo_composite = Some(statement.clone()); } } pub fn typeinfo_enum(&self) -> Option { - self.state.lock().typeinfo_enum.clone() + self.cached_typeinfo.lock().typeinfo_enum.clone() } pub fn set_typeinfo_enum(&self, statement: &Statement) { // We only insert the statement if there isn't already a cached // statement (this is safe as they are prepared statements for the same // query). - // - // Note: We need to be sure that we don't drop a Statement while holding - // the state lock as its drop handling will call `with_buf`, which tries - // to take the lock. - let mut state = self.state.lock(); - if state.typeinfo_enum.is_none() { - state.typeinfo_enum = Some(statement.clone()); + let mut cache = self.cached_typeinfo.lock(); + if cache.typeinfo_enum.is_none() { + cache.typeinfo_enum = Some(statement.clone()); } } pub fn type_(&self, oid: Oid) -> Option { - self.state.lock().types.get(&oid).cloned() + self.cached_typeinfo.lock().types.get(&oid).cloned() } pub fn set_type(&self, oid: Oid, type_: &Type) { - self.state.lock().types.insert(oid, type_.clone()); + self.cached_typeinfo.lock().types.insert(oid, type_.clone()); } pub fn clear_type_cache(&self) { - self.state.lock().types.clear(); + self.cached_typeinfo.lock().types.clear(); } + /// Call the given function with a buffer to be used when writing out + /// postgres commands. pub fn with_buf(&self, f: F) -> R where F: FnOnce(&mut BytesMut) -> R, { - let mut state = self.state.lock(); - let r = f(&mut state.buf); - state.buf.clear(); + let mut buffer = self.buffer.lock(); + let r = f(&mut buffer); + buffer.clear(); r } } @@ -199,13 +199,8 @@ impl Client { Client { inner: Arc::new(InnerClient { sender, - state: Mutex::new(State { - typeinfo: None, - typeinfo_composite: None, - typeinfo_enum: None, - types: HashMap::new(), - buf: BytesMut::new(), - }), + cached_typeinfo: Default::default(), + buffer: Default::default(), }), #[cfg(feature = "runtime")] socket_config: None, From 844a1bd145c0099ea1a31de145a6ecc8fc2a699b Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Sat, 15 May 2021 10:25:14 +0100 Subject: [PATCH 113/420] Revert change back to always setting the cached statement --- tokio-postgres/src/client.rs | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 4e8babf1d..4a099d941 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -101,17 +101,7 @@ impl InnerClient { } pub fn set_typeinfo(&self, statement: &Statement) { - // We only insert the statement if there isn't already a cached - // statement (this is safe as they are prepared statements for the same - // query). - // - // Note: We need to be sure that we don't drop a Statement while holding - // the state lock as its drop handling will call `with_buf`, which tries - // to take the lock. - let mut cache = self.cached_typeinfo.lock(); - if cache.typeinfo.is_none() { - cache.typeinfo = Some(statement.clone()); - } + self.cached_typeinfo.lock().typeinfo = Some(statement.clone()); } pub fn typeinfo_composite(&self) -> Option { @@ -119,13 +109,7 @@ impl InnerClient { } pub fn set_typeinfo_composite(&self, statement: &Statement) { - // We only insert the statement if there isn't already a cached - // statement (this is safe as they are prepared statements for the same - // query). - let mut cache = self.cached_typeinfo.lock(); - if cache.typeinfo_composite.is_none() { - cache.typeinfo_composite = Some(statement.clone()); - } + self.cached_typeinfo.lock().typeinfo_composite = Some(statement.clone()); } pub fn typeinfo_enum(&self) -> Option { @@ -133,13 +117,7 @@ impl InnerClient { } pub fn set_typeinfo_enum(&self, statement: &Statement) { - // We only insert the statement if there isn't already a cached - // statement (this is safe as they are prepared statements for the same - // query). - let mut cache = self.cached_typeinfo.lock(); - if cache.typeinfo_enum.is_none() { - cache.typeinfo_enum = Some(statement.clone()); - } + self.cached_typeinfo.lock().typeinfo_enum = Some(statement.clone()); } pub fn type_(&self, oid: Oid) -> Option { From 52de2693670ee4b1a6d571f176ea4dd44117db43 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 18 May 2021 20:47:26 -0400 Subject: [PATCH 114/420] fix clippy --- postgres-protocol/src/message/backend.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/postgres-protocol/src/message/backend.rs b/postgres-protocol/src/message/backend.rs index 68b5aa6e5..45e5c4074 100644 --- a/postgres-protocol/src/message/backend.rs +++ b/postgres-protocol/src/message/backend.rs @@ -450,9 +450,9 @@ impl CopyDataBody { } pub struct CopyInResponseBody { - storage: Bytes, - len: u16, format: u8, + len: u16, + storage: Bytes, } impl CopyInResponseBody { @@ -504,9 +504,9 @@ impl<'a> FallibleIterator for ColumnFormats<'a> { } pub struct CopyOutResponseBody { - storage: Bytes, - len: u16, format: u8, + len: u16, + storage: Bytes, } impl CopyOutResponseBody { From ca6d4b816221214798bc68f2b182f9fa822e115f Mon Sep 17 00:00:00 2001 From: Petros Angelatos Date: Mon, 24 May 2021 17:54:24 +0200 Subject: [PATCH 115/420] tokio-postgres: buffer sockets to avoid excessive syscalls The current implementation forwards all read requests to the operating system through the socket causing excessive system calls. The effect is magnified when the underlying Socket is wrapped around a TLS implementation. This commit changes the underlying socket to be read-buffered by default with a buffer size of 16K, following the implementation of the official client. Signed-off-by: Petros Angelatos --- postgres-native-tls/src/lib.rs | 5 +++-- postgres-openssl/src/lib.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/postgres-native-tls/src/lib.rs b/postgres-native-tls/src/lib.rs index 70e34812d..2f2e6e6ad 100644 --- a/postgres-native-tls/src/lib.rs +++ b/postgres-native-tls/src/lib.rs @@ -51,7 +51,7 @@ use std::future::Future; use std::io; use std::pin::Pin; use std::task::{Context, Poll}; -use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; +use tokio::io::{AsyncRead, AsyncWrite, BufReader, ReadBuf}; use tokio_postgres::tls; #[cfg(feature = "runtime")] use tokio_postgres::tls::MakeTlsConnect; @@ -115,6 +115,7 @@ where type Future = Pin, native_tls::Error>> + Send>>; fn connect(self, stream: S) -> Self::Future { + let stream = BufReader::with_capacity(8192, stream); let future = async move { let stream = self.connector.connect(&self.domain, stream).await?; @@ -126,7 +127,7 @@ where } /// The stream returned by `TlsConnector`. -pub struct TlsStream(tokio_native_tls::TlsStream); +pub struct TlsStream(tokio_native_tls::TlsStream>); impl AsyncRead for TlsStream where diff --git a/postgres-openssl/src/lib.rs b/postgres-openssl/src/lib.rs index dce3dff5d..f3c0b9309 100644 --- a/postgres-openssl/src/lib.rs +++ b/postgres-openssl/src/lib.rs @@ -57,7 +57,7 @@ use std::pin::Pin; #[cfg(feature = "runtime")] use std::sync::Arc; use std::task::{Context, Poll}; -use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; +use tokio::io::{AsyncRead, AsyncWrite, BufReader, ReadBuf}; use tokio_openssl::SslStream; use tokio_postgres::tls; #[cfg(feature = "runtime")] @@ -140,6 +140,7 @@ where type Future = Pin, Self::Error>> + Send>>; fn connect(self, stream: S) -> Self::Future { + let stream = BufReader::with_capacity(8192, stream); let future = async move { let ssl = self.ssl.into_ssl(&self.domain)?; let mut stream = SslStream::new(ssl, stream)?; @@ -182,7 +183,7 @@ impl Error for ConnectError { } /// The stream returned by `TlsConnector`. -pub struct TlsStream(SslStream); +pub struct TlsStream(SslStream>); impl AsyncRead for TlsStream where From b03ffcd043722ec74d1075514bf9ad8e061954b8 Mon Sep 17 00:00:00 2001 From: Marcin Pajkowski Date: Sat, 29 May 2021 23:43:22 +0200 Subject: [PATCH 116/420] expose SimpleQueryRow's column names --- tokio-postgres/src/row.rs | 19 +++++++++++++++++-- tokio-postgres/src/simple_query.rs | 21 +++++++++++++++++++-- tokio-postgres/tests/test/main.rs | 4 ++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/tokio-postgres/src/row.rs b/tokio-postgres/src/row.rs index 842216ad2..e3ed696c1 100644 --- a/tokio-postgres/src/row.rs +++ b/tokio-postgres/src/row.rs @@ -1,6 +1,7 @@ //! Rows. use crate::row::sealed::{AsName, Sealed}; +use crate::simple_query::SimpleColumn; use crate::statement::Column; use crate::types::{FromSql, Type, WrongType}; use crate::{Error, Statement}; @@ -188,16 +189,25 @@ impl Row { } } +impl AsName for SimpleColumn { + fn as_name(&self) -> &str { + self.name() + } +} + /// A row of data returned from the database by a simple query. pub struct SimpleQueryRow { - columns: Arc<[String]>, + columns: Arc<[SimpleColumn]>, body: DataRowBody, ranges: Vec>>, } impl SimpleQueryRow { #[allow(clippy::new_ret_no_self)] - pub(crate) fn new(columns: Arc<[String]>, body: DataRowBody) -> Result { + pub(crate) fn new( + columns: Arc<[SimpleColumn]>, + body: DataRowBody, + ) -> Result { let ranges = body.ranges().collect().map_err(Error::parse)?; Ok(SimpleQueryRow { columns, @@ -206,6 +216,11 @@ impl SimpleQueryRow { }) } + /// Returns information about the columns of data in the row. + pub fn columns(&self) -> &[SimpleColumn] { + &self.columns + } + /// Determines if the row contains no values. pub fn is_empty(&self) -> bool { self.len() == 0 diff --git a/tokio-postgres/src/simple_query.rs b/tokio-postgres/src/simple_query.rs index 82ac35664..ade2e1d6d 100644 --- a/tokio-postgres/src/simple_query.rs +++ b/tokio-postgres/src/simple_query.rs @@ -14,6 +14,22 @@ use std::pin::Pin; use std::sync::Arc; use std::task::{Context, Poll}; +/// Information about a column of a single query row. +pub struct SimpleColumn { + name: String, +} + +impl SimpleColumn { + pub(crate) fn new(name: String) -> SimpleColumn { + SimpleColumn { name } + } + + /// Returns the name of the column. + pub fn name(&self) -> &str { + &self.name + } +} + pub async fn simple_query(client: &InnerClient, query: &str) -> Result { debug!("executing simple query: {}", query); @@ -56,7 +72,7 @@ pin_project! { /// A stream of simple query results. pub struct SimpleQueryStream { responses: Responses, - columns: Option>, + columns: Option>, #[pin] _p: PhantomPinned, } @@ -86,10 +102,11 @@ impl Stream for SimpleQueryStream { Message::RowDescription(body) => { let columns = body .fields() - .map(|f| Ok(f.name().to_string())) + .map(|f| Ok(SimpleColumn::new(f.name().to_string()))) .collect::>() .map_err(Error::parse)? .into(); + *this.columns = Some(columns); } Message::DataRow(body) => { diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index c367dbea3..c0b4bf202 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -282,6 +282,8 @@ async fn simple_query() { } match &messages[2] { SimpleQueryMessage::Row(row) => { + assert_eq!(row.columns().get(0).map(|c| c.name()), Some("id")); + assert_eq!(row.columns().get(1).map(|c| c.name()), Some("name")); assert_eq!(row.get(0), Some("1")); assert_eq!(row.get(1), Some("steven")); } @@ -289,6 +291,8 @@ async fn simple_query() { } match &messages[3] { SimpleQueryMessage::Row(row) => { + assert_eq!(row.columns().get(0).map(|c| c.name()), Some("id")); + assert_eq!(row.columns().get(1).map(|c| c.name()), Some("name")); assert_eq!(row.get(0), Some("2")); assert_eq!(row.get(1), Some("joe")); } From a8383dcc2970d5720ee8097c48c1d4c507a24eab Mon Sep 17 00:00:00 2001 From: Tim Anderson Date: Thu, 3 Jun 2021 10:54:37 +1000 Subject: [PATCH 117/420] Add support for eui48 version 1.0 --- postgres-types/Cargo.toml | 2 ++ postgres-types/src/eui48_1.rs | 27 ++++++++++++++++++++++ postgres-types/src/lib.rs | 2 ++ postgres/Cargo.toml | 1 + postgres/src/lib.rs | 3 ++- tokio-postgres/Cargo.toml | 2 ++ tokio-postgres/src/lib.rs | 3 ++- tokio-postgres/tests/test/types/eui48_1.rs | 18 +++++++++++++++ tokio-postgres/tests/test/types/mod.rs | 2 ++ 9 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 postgres-types/src/eui48_1.rs create mode 100644 tokio-postgres/tests/test/types/eui48_1.rs diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 1d7f2cc9a..b258cee12 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -15,6 +15,7 @@ derive = ["postgres-derive"] with-bit-vec-0_6 = ["bit-vec-06"] with-chrono-0_4 = ["chrono-04"] with-eui48-0_4 = ["eui48-04"] +with-eui48-1 = ["eui48-1"] with-geo-types-0_6 = ["geo-types-06"] with-geo-types-0_7 = ["geo-types-0_7"] with-serde_json-1 = ["serde-1", "serde_json-1"] @@ -30,6 +31,7 @@ postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-deri bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } chrono-04 = { version = "0.4.16", package = "chrono", default-features = false, features = ["clock"], optional = true } eui48-04 = { version = "0.4", package = "eui48", optional = true } +eui48-1 = { version = "1.0", package = "eui48", optional = true } geo-types-06 = { version = "0.6", package = "geo-types", optional = true } geo-types-0_7 = { version = "0.7", package = "geo-types", optional = true } serde-1 = { version = "1.0", package = "serde", optional = true } diff --git a/postgres-types/src/eui48_1.rs b/postgres-types/src/eui48_1.rs new file mode 100644 index 000000000..4c35e63ce --- /dev/null +++ b/postgres-types/src/eui48_1.rs @@ -0,0 +1,27 @@ +use bytes::BytesMut; +use eui48_1::MacAddress; +use postgres_protocol::types; +use std::error::Error; + +use crate::{FromSql, IsNull, ToSql, Type}; + +impl<'a> FromSql<'a> for MacAddress { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let bytes = types::macaddr_from_sql(raw)?; + Ok(MacAddress::new(bytes)) + } + + accepts!(MACADDR); +} + +impl ToSql for MacAddress { + fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { + let mut bytes = [0; 6]; + bytes.copy_from_slice(self.as_bytes()); + types::macaddr_to_sql(bytes, w); + Ok(IsNull::No) + } + + accepts!(MACADDR); + to_sql_checked!(); +} diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 5c483bd76..ed6f75cf5 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -194,6 +194,8 @@ mod bit_vec_06; mod chrono_04; #[cfg(feature = "with-eui48-0_4")] mod eui48_04; +#[cfg(feature = "with-eui48-1")] +mod eui48_1; #[cfg(feature = "with-geo-types-0_6")] mod geo_types_06; #[cfg(feature = "with-geo-types-0_7")] diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 18219782d..c7c0746f0 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -24,6 +24,7 @@ circle-ci = { repository = "sfackler/rust-postgres" } with-bit-vec-0_6 = ["tokio-postgres/with-bit-vec-0_6"] with-chrono-0_4 = ["tokio-postgres/with-chrono-0_4"] 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"] with-geo-types-0_7 = ["tokio-postgres/with-geo-types-0_7"] with-serde_json-1 = ["tokio-postgres/with-serde_json-1"] diff --git a/postgres/src/lib.rs b/postgres/src/lib.rs index 4513aeef7..7d96bfd9f 100644 --- a/postgres/src/lib.rs +++ b/postgres/src/lib.rs @@ -55,7 +55,8 @@ //! | ------- | ----------- | ------------------ | ------- | //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | -//! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | +//! | `with-eui48-0_4` | Enable support for the 0.4 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | +//! | `with-eui48-1` | Enable support for the 1.0 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 1.0 | no | //! | `with-geo-types-0_6` | Enable support for the 0.6 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.6.0) 0.6 | no | //! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 780c31963..fa1b50397 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -30,6 +30,7 @@ runtime = ["tokio/net", "tokio/time"] with-bit-vec-0_6 = ["postgres-types/with-bit-vec-0_6"] with-chrono-0_4 = ["postgres-types/with-chrono-0_4"] 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"] with-geo-types-0_7 = ["postgres-types/with-geo-types-0_7"] with-serde_json-1 = ["postgres-types/with-serde_json-1"] @@ -61,6 +62,7 @@ criterion = "0.3" bit-vec-06 = { version = "0.6", package = "bit-vec" } chrono-04 = { version = "0.4", package = "chrono", default-features = false } eui48-04 = { version = "0.4", package = "eui48" } +eui48-1 = { version = "1.0", package = "eui48" } geo-types-06 = { version = "0.6", package = "geo-types" } geo-types-07 = { version = "0.7", package = "geo-types" } serde-1 = { version = "1.0", package = "serde" } diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 77713bb11..6dd0b0151 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -106,7 +106,8 @@ //! | `runtime` | Enable convenience API for the connection process based on the `tokio` crate. | [tokio](https://crates.io/crates/tokio) 1.0 with the features `net` and `time` | yes | //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | -//! | `with-eui48-0_4` | Enable support for the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | +//! | `with-eui48-0_4` | Enable support for the 0.4 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | +//! | `with-eui48-1` | Enable support for the 1.0 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 1.0 | no | //! | `with-geo-types-0_6` | Enable support for the 0.6 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.6.0) 0.6 | no | //! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | diff --git a/tokio-postgres/tests/test/types/eui48_1.rs b/tokio-postgres/tests/test/types/eui48_1.rs new file mode 100644 index 000000000..0c22e9e87 --- /dev/null +++ b/tokio-postgres/tests/test/types/eui48_1.rs @@ -0,0 +1,18 @@ +use eui48_1::MacAddress; + +use crate::types::test_type; + +#[tokio::test] +async fn test_eui48_params() { + test_type( + "MACADDR", + &[ + ( + Some(MacAddress::parse_str("12-34-56-AB-CD-EF").unwrap()), + "'12-34-56-ab-cd-ef'", + ), + (None, "NULL"), + ], + ) + .await +} diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index bc31ece71..85eed0e27 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -19,6 +19,8 @@ mod bit_vec_06; mod chrono_04; #[cfg(feature = "with-eui48-0_4")] mod eui48_04; +#[cfg(feature = "with-eui48-1")] +mod eui48_1; #[cfg(feature = "with-geo-types-0_6")] mod geo_types_06; #[cfg(feature = "with-geo-types-0_7")] From 57cacb65fe24762ccfc7889c06b9e906a6408588 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 21 Jun 2021 21:30:41 -0400 Subject: [PATCH 118/420] Upgrade phf --- codegen/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- tokio-postgres/src/error/sqlstate.rs | 552 +++++++++++++-------------- 3 files changed, 278 insertions(+), 278 deletions(-) diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index 8ff4d58be..fc02751cf 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Steven Fackler "] [dependencies] -phf_codegen = "0.8" +phf_codegen = "0.9" regex = "1.0" marksman_escape = "0.1" linked-hash-map = "0.5" diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index fa1b50397..3a1537a87 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -47,7 +47,7 @@ log = "0.4" parking_lot = "0.11" percent-encoding = "2.0" pin-project-lite = "0.2" -phf = "0.8" +phf = "0.9" postgres-protocol = { version = "0.6.1", path = "../postgres-protocol" } postgres-types = { version = "0.2.1", path = "../postgres-types" } socket2 = "0.4" diff --git a/tokio-postgres/src/error/sqlstate.rs b/tokio-postgres/src/error/sqlstate.rs index 125124d12..1996d9b13 100644 --- a/tokio-postgres/src/error/sqlstate.rs +++ b/tokio-postgres/src/error/sqlstate.rs @@ -1340,319 +1340,319 @@ enum Inner { #[rustfmt::skip] static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ::phf::Map { - key: 732231254413039614, + key: 12913932095322966823, disps: ::phf::Slice::Static(&[ - (0, 6), + (0, 12), + (0, 18), + (0, 25), + (0, 109), + (0, 147), + (0, 74), (0, 0), - (0, 218), - (0, 11), - (0, 31), - (0, 91), - (0, 55), + (7, 117), + (5, 221), + (0, 26), + (1, 45), + (0, 93), + (0, 25), + (0, 61), + (1, 221), + (10, 17), (0, 77), - (0, 72), + (2, 3), + (0, 216), + (0, 0), (0, 1), - (0, 73), - (1, 159), - (4, 4), - (0, 18), - (2, 100), - (0, 19), - (0, 16), - (0, 22), - (0, 51), + (1, 168), + (0, 64), + (0, 2), + (0, 7), + (1, 37), + (0, 83), + (3, 24), (0, 0), + (0, 109), + (18, 9), + (1, 230), (0, 0), - (1, 2), - (2, 177), - (0, 10), - (1, 192), + (0, 4), + (0, 171), (0, 0), - (5, 245), - (0, 106), - (6, 243), - (47, 195), - (0, 146), - (4, 154), - (0, 2), - (4, 78), - (0, 196), - (0, 8), - (2, 146), - (0, 15), - (0, 170), - (0, 5), - (10, 18), - (0, 30), - (0, 33), - (0, 2), + (34, 97), + (2, 126), + (44, 49), + (5, 182), + (0, 1), + (0, 1), + (0, 71), + (0, 4), + (5, 164), (0, 0), - (47, 181), - (0, 144), - (39, 231), - (39, 173), - (0, 57), - (0, 7), - (1, 154), + (0, 96), + (13, 58), + (0, 58), + (0, 242), + (0, 72), + (16, 53), ]), entries: ::phf::Slice::Static(&[ - ("22P04", SqlState::BAD_COPY_FILE_FORMAT), - ("39001", SqlState::E_R_I_E_INVALID_SQLSTATE_RETURNED), - ("2201F", SqlState::INVALID_ARGUMENT_FOR_POWER_FUNCTION), - ("54000", SqlState::PROGRAM_LIMIT_EXCEEDED), - ("2200T", SqlState::INVALID_XML_PROCESSING_INSTRUCTION), - ("01000", SqlState::WARNING), - ("02000", SqlState::NO_DATA), - ("40003", SqlState::T_R_STATEMENT_COMPLETION_UNKNOWN), - ("42702", SqlState::AMBIGUOUS_COLUMN), - ("HV000", SqlState::FDW_ERROR), - ("2203A", SqlState::SQL_JSON_MEMBER_NOT_FOUND), - ("22021", SqlState::CHARACTER_NOT_IN_REPERTOIRE), - ("HV006", SqlState::FDW_INVALID_DATA_TYPE_DESCRIPTORS), - ("40000", SqlState::TRANSACTION_ROLLBACK), - ("57P01", SqlState::ADMIN_SHUTDOWN), ("22034", SqlState::MORE_THAN_ONE_SQL_JSON_ITEM), - ("54023", SqlState::TOO_MANY_ARGUMENTS), - ("22027", SqlState::TRIM_ERROR), - ("2203C", SqlState::SQL_JSON_OBJECT_NOT_FOUND), - ("22P06", SqlState::NONSTANDARD_USE_OF_ESCAPE_CHARACTER), - ("72000", SqlState::SNAPSHOT_TOO_OLD), - ("25004", SqlState::INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION), - ("2BP01", SqlState::DEPENDENT_OBJECTS_STILL_EXIST), - ("42P11", SqlState::INVALID_CURSOR_DEFINITION), - ("HV00J", SqlState::FDW_OPTION_NAME_NOT_FOUND), - ("42804", SqlState::DATATYPE_MISMATCH), - ("39004", SqlState::E_R_I_E_NULL_VALUE_NOT_ALLOWED), + ("40P01", SqlState::T_R_DEADLOCK_DETECTED), ("42703", SqlState::UNDEFINED_COLUMN), - ("2203E", SqlState::TOO_MANY_JSON_OBJECT_MEMBERS), - ("42P12", SqlState::INVALID_DATABASE_DEFINITION), - ("23503", SqlState::FOREIGN_KEY_VIOLATION), - ("25003", SqlState::INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION), - ("22P03", SqlState::INVALID_BINARY_REPRESENTATION), - ("40002", SqlState::T_R_INTEGRITY_CONSTRAINT_VIOLATION), - ("58030", SqlState::IO_ERROR), - ("01004", SqlState::WARNING_STRING_DATA_RIGHT_TRUNCATION), - ("22019", SqlState::INVALID_ESCAPE_CHARACTER), - ("42P20", SqlState::WINDOWING_ERROR), - ("3D000", SqlState::INVALID_CATALOG_NAME), - ("22001", SqlState::STRING_DATA_RIGHT_TRUNCATION), - ("F0000", SqlState::CONFIG_FILE_ERROR), - ("25005", SqlState::NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION), - ("42883", SqlState::UNDEFINED_FUNCTION), - ("42P06", SqlState::DUPLICATE_SCHEMA), - ("42P17", SqlState::INVALID_OBJECT_DEFINITION), - ("HV002", SqlState::FDW_DYNAMIC_PARAMETER_VALUE_NEEDED), - ("0F001", SqlState::L_E_INVALID_SPECIFICATION), - ("57014", SqlState::QUERY_CANCELED), - ("22033", SqlState::INVALID_SQL_JSON_SUBSCRIPT), - ("2F004", SqlState::S_R_E_READING_SQL_DATA_NOT_PERMITTED), - ("42611", SqlState::INVALID_COLUMN_DEFINITION), - ("42939", SqlState::RESERVED_NAME), - ("0P000", SqlState::INVALID_ROLE_SPECIFICATION), - ("53200", SqlState::OUT_OF_MEMORY), - ("42809", SqlState::WRONG_OBJECT_TYPE), - ("2202H", SqlState::INVALID_TABLESAMPLE_ARGUMENT), - ("42P16", SqlState::INVALID_TABLE_DEFINITION), - ("24000", SqlState::INVALID_CURSOR_STATE), - ("42P13", SqlState::INVALID_FUNCTION_DEFINITION), - ("22007", SqlState::INVALID_DATETIME_FORMAT), - ("2D000", SqlState::INVALID_TRANSACTION_TERMINATION), - ("53100", SqlState::DISK_FULL), - ("P0003", SqlState::TOO_MANY_ROWS), - ("22016", SqlState::INVALID_ARGUMENT_FOR_NTH_VALUE), - ("2F002", SqlState::S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED), - ("42830", SqlState::INVALID_FOREIGN_KEY), - ("27000", SqlState::TRIGGERED_DATA_CHANGE_VIOLATION), - ("0Z002", SqlState::STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER), - ("53000", SqlState::INSUFFICIENT_RESOURCES), - ("23502", SqlState::NOT_NULL_VIOLATION), - ("XX000", SqlState::INTERNAL_ERROR), - ("58P01", SqlState::UNDEFINED_FILE), - ("42601", SqlState::SYNTAX_ERROR), - ("02001", SqlState::NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED), - ("42P09", SqlState::AMBIGUOUS_ALIAS), - ("22P02", SqlState::INVALID_TEXT_REPRESENTATION), - ("55P02", SqlState::CANT_CHANGE_RUNTIME_PARAM), - ("2F003", SqlState::S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), - ("53300", SqlState::TOO_MANY_CONNECTIONS), - ("25P02", SqlState::IN_FAILED_SQL_TRANSACTION), - ("42P03", SqlState::DUPLICATE_CURSOR), - ("XX002", SqlState::INDEX_CORRUPTED), - ("22010", SqlState::INVALID_INDICATOR_PARAMETER_VALUE), - ("01006", SqlState::WARNING_PRIVILEGE_NOT_REVOKED), - ("3B001", SqlState::S_E_INVALID_SPECIFICATION), - ("42P21", SqlState::COLLATION_MISMATCH), ("42P07", SqlState::DUPLICATE_TABLE), - ("22013", SqlState::INVALID_PRECEDING_OR_FOLLOWING_SIZE), - ("0Z000", SqlState::DIAGNOSTICS_EXCEPTION), ("55P04", SqlState::UNSAFE_NEW_ENUM_VALUE_USAGE), - ("42000", SqlState::SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION), - ("XX001", SqlState::DATA_CORRUPTED), - ("25008", SqlState::HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL), - ("HV00M", SqlState::FDW_UNABLE_TO_CREATE_REPLY), - ("39000", SqlState::EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), - ("22032", SqlState::INVALID_JSON_TEXT), ("25006", SqlState::READ_ONLY_SQL_TRANSACTION), - ("01P01", SqlState::WARNING_DEPRECATED_FEATURE), - ("42725", SqlState::AMBIGUOUS_FUNCTION), - ("42602", SqlState::INVALID_NAME), - ("2201W", SqlState::INVALID_ROW_COUNT_IN_LIMIT_CLAUSE), - ("42P05", SqlState::DUPLICATE_PSTATEMENT), + ("2201X", SqlState::INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE), ("HV021", SqlState::FDW_INCONSISTENT_DESCRIPTOR_INFORMATION), - ("57P03", SqlState::CANNOT_CONNECT_NOW), - ("58P02", SqlState::DUPLICATE_FILE), - ("42P22", SqlState::INDETERMINATE_COLLATION), - ("0B000", SqlState::INVALID_TRANSACTION_INITIATION), - ("0100C", SqlState::WARNING_DYNAMIC_RESULT_SETS_RETURNED), - ("22015", SqlState::INTERVAL_FIELD_OVERFLOW), - ("2200S", SqlState::INVALID_XML_COMMENT), - ("2200M", SqlState::INVALID_XML_DOCUMENT), - ("HV001", SqlState::FDW_OUT_OF_MEMORY), - ("25001", SqlState::ACTIVE_SQL_TRANSACTION), - ("22002", SqlState::NULL_VALUE_NO_INDICATOR_PARAMETER), + ("42P02", SqlState::UNDEFINED_PARAMETER), + ("HV00C", SqlState::FDW_INVALID_OPTION_INDEX), + ("08003", SqlState::CONNECTION_DOES_NOT_EXIST), + ("02000", SqlState::NO_DATA), + ("24000", SqlState::INVALID_CURSOR_STATE), + ("2203C", SqlState::SQL_JSON_OBJECT_NOT_FOUND), + ("42601", SqlState::SYNTAX_ERROR), + ("22012", SqlState::DIVISION_BY_ZERO), + ("2203B", SqlState::SQL_JSON_NUMBER_NOT_FOUND), + ("P0003", SqlState::TOO_MANY_ROWS), + ("57P04", SqlState::DATABASE_DROPPED), + ("27000", SqlState::TRIGGERED_DATA_CHANGE_VIOLATION), + ("42P08", SqlState::AMBIGUOUS_PARAMETER), + ("3F000", SqlState::INVALID_SCHEMA_NAME), + ("42883", SqlState::UNDEFINED_FUNCTION), + ("20000", SqlState::CASE_NOT_FOUND), + ("2200G", SqlState::MOST_SPECIFIC_TYPE_MISMATCH), + ("42939", SqlState::RESERVED_NAME), + ("42602", SqlState::INVALID_NAME), + ("HV004", SqlState::FDW_INVALID_DATA_TYPE), + ("HV007", SqlState::FDW_INVALID_COLUMN_NAME), ("2F005", SqlState::S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), - ("428C9", SqlState::GENERATED_ALWAYS), - ("25P01", SqlState::NO_ACTIVE_SQL_TRANSACTION), - ("HV091", SqlState::FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER), - ("2200C", SqlState::INVALID_USE_OF_ESCAPE_CHARACTER), - ("HV008", SqlState::FDW_INVALID_COLUMN_NUMBER), - ("2200F", SqlState::ZERO_LENGTH_CHARACTER_STRING), - ("54001", SqlState::STATEMENT_TOO_COMPLEX), + ("22030", SqlState::DUPLICATE_JSON_OBJECT_KEY_VALUE), + ("53100", SqlState::DISK_FULL), + ("HV005", SqlState::FDW_COLUMN_NAME_NOT_FOUND), + ("2200H", SqlState::SEQUENCE_GENERATOR_LIMIT_EXCEEDED), + ("2201W", SqlState::INVALID_ROW_COUNT_IN_LIMIT_CLAUSE), ("42712", SqlState::DUPLICATE_ALIAS), - ("HV00A", SqlState::FDW_INVALID_STRING_FORMAT), - ("42710", SqlState::DUPLICATE_OBJECT), - ("54011", SqlState::TOO_MANY_COLUMNS), - ("42P19", SqlState::INVALID_RECURSION), - ("42501", SqlState::INSUFFICIENT_PRIVILEGE), + ("42622", SqlState::NAME_TOO_LONG), + ("22035", SqlState::NO_SQL_JSON_ITEM), + ("42P18", SqlState::INDETERMINATE_DATATYPE), + ("39P01", SqlState::E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + ("01000", SqlState::WARNING), + ("2F004", SqlState::S_R_E_READING_SQL_DATA_NOT_PERMITTED), + ("22023", SqlState::INVALID_PARAMETER_VALUE), + ("2200T", SqlState::INVALID_XML_PROCESSING_INSTRUCTION), + ("22013", SqlState::INVALID_PRECEDING_OR_FOLLOWING_SIZE), + ("57P01", SqlState::ADMIN_SHUTDOWN), + ("2202E", SqlState::ARRAY_ELEMENT_ERROR), + ("22018", SqlState::INVALID_CHARACTER_VALUE_FOR_CAST), + ("0F000", SqlState::LOCATOR_EXCEPTION), + ("2D000", SqlState::INVALID_TRANSACTION_TERMINATION), + ("HV009", SqlState::FDW_INVALID_USE_OF_NULL_POINTER), ("57000", SqlState::OPERATOR_INTERVENTION), ("25002", SqlState::BRANCH_TRANSACTION_ALREADY_ACTIVE), - ("22039", SqlState::SQL_JSON_ARRAY_NOT_FOUND), - ("P0002", SqlState::NO_DATA_FOUND), + ("25004", SqlState::INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION), + ("22009", SqlState::INVALID_TIME_ZONE_DISPLACEMENT_VALUE), + ("HV090", SqlState::FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH), + ("42725", SqlState::AMBIGUOUS_FUNCTION), + ("2F003", SqlState::S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), + ("44000", SqlState::WITH_CHECK_OPTION_VIOLATION), + ("22032", SqlState::INVALID_JSON_TEXT), + ("22036", SqlState::NON_NUMERIC_SQL_JSON_ITEM), + ("2201E", SqlState::INVALID_ARGUMENT_FOR_LOG), + ("25P02", SqlState::IN_FAILED_SQL_TRANSACTION), + ("22001", SqlState::STRING_DATA_RIGHT_TRUNCATION), + ("2201F", SqlState::INVALID_ARGUMENT_FOR_POWER_FUNCTION), + ("01006", SqlState::WARNING_PRIVILEGE_NOT_REVOKED), + ("428C9", SqlState::GENERATED_ALWAYS), + ("22003", SqlState::NUMERIC_VALUE_OUT_OF_RANGE), + ("22P01", SqlState::FLOATING_POINT_EXCEPTION), + ("HV00M", SqlState::FDW_UNABLE_TO_CREATE_REPLY), ("2201G", SqlState::INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION), - ("22012", SqlState::DIVISION_BY_ZERO), - ("42P10", SqlState::INVALID_COLUMN_REFERENCE), + ("34000", SqlState::INVALID_CURSOR_NAME), + ("42846", SqlState::CANNOT_COERCE), + ("2201B", SqlState::INVALID_REGULAR_EXPRESSION), + ("2202G", SqlState::INVALID_TABLESAMPLE_REPEAT), + ("42704", SqlState::UNDEFINED_OBJECT), + ("72000", SqlState::SNAPSHOT_TOO_OLD), + ("53400", SqlState::CONFIGURATION_LIMIT_EXCEEDED), + ("HV00L", SqlState::FDW_UNABLE_TO_CREATE_EXECUTION), + ("2B000", SqlState::DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST), + ("22010", SqlState::INVALID_INDICATOR_PARAMETER_VALUE), + ("54001", SqlState::STATEMENT_TOO_COMPLEX), + ("53200", SqlState::OUT_OF_MEMORY), + ("38001", SqlState::E_R_E_CONTAINING_SQL_NOT_PERMITTED), + ("22022", SqlState::INDICATOR_OVERFLOW), + ("2203E", SqlState::TOO_MANY_JSON_OBJECT_MEMBERS), + ("XX000", SqlState::INTERNAL_ERROR), + ("22025", SqlState::INVALID_ESCAPE_SEQUENCE), + ("09000", SqlState::TRIGGERED_ACTION_EXCEPTION), + ("HV008", SqlState::FDW_INVALID_COLUMN_NUMBER), + ("25P01", SqlState::NO_ACTIVE_SQL_TRANSACTION), + ("23505", SqlState::UNIQUE_VIOLATION), + ("3B000", SqlState::SAVEPOINT_EXCEPTION), + ("F0000", SqlState::CONFIG_FILE_ERROR), + ("54011", SqlState::TOO_MANY_COLUMNS), + ("XX002", SqlState::INDEX_CORRUPTED), + ("2203F", SqlState::SQL_JSON_SCALAR_REQUIRED), + ("42P12", SqlState::INVALID_DATABASE_DEFINITION), ("HV00B", SqlState::FDW_INVALID_HANDLE), - ("38003", SqlState::E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), + ("55006", SqlState::OBJECT_IN_USE), + ("42P01", SqlState::UNDEFINED_TABLE), ("25P03", SqlState::IDLE_IN_TRANSACTION_SESSION_TIMEOUT), - ("F0001", SqlState::LOCK_FILE_EXISTS), - ("08001", SqlState::SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION), - ("2203D", SqlState::TOO_MANY_JSON_ARRAY_ELEMENTS), - ("P0000", SqlState::PLPGSQL_ERROR), - ("28000", SqlState::INVALID_AUTHORIZATION_SPECIFICATION), - ("2200D", SqlState::INVALID_ESCAPE_OCTET), - ("55P03", SqlState::LOCK_NOT_AVAILABLE), - ("23505", SqlState::UNIQUE_VIOLATION), - ("39P01", SqlState::E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), - ("44000", SqlState::WITH_CHECK_OPTION_VIOLATION), - ("22030", SqlState::DUPLICATE_JSON_OBJECT_KEY_VALUE), + ("22037", SqlState::NON_UNIQUE_KEYS_IN_A_JSON_OBJECT), + ("2203A", SqlState::SQL_JSON_MEMBER_NOT_FOUND), ("P0004", SqlState::ASSERT_FAILURE), - ("2200G", SqlState::MOST_SPECIFIC_TYPE_MISMATCH), - ("2F000", SqlState::SQL_ROUTINE_EXCEPTION), - ("26000", SqlState::INVALID_SQL_STATEMENT_NAME), - ("2202G", SqlState::INVALID_TABLESAMPLE_REPEAT), - ("22003", SqlState::NUMERIC_VALUE_OUT_OF_RANGE), + ("58000", SqlState::SYSTEM_ERROR), + ("42P21", SqlState::COLLATION_MISMATCH), + ("57P02", SqlState::CRASH_SHUTDOWN), + ("42830", SqlState::INVALID_FOREIGN_KEY), + ("0LP01", SqlState::INVALID_GRANT_OPERATION), + ("22P02", SqlState::INVALID_TEXT_REPRESENTATION), + ("22039", SqlState::SQL_JSON_ARRAY_NOT_FOUND), + ("28P01", SqlState::INVALID_PASSWORD), + ("22011", SqlState::SUBSTRING_ERROR), + ("HV00J", SqlState::FDW_OPTION_NAME_NOT_FOUND), + ("2200C", SqlState::INVALID_USE_OF_ESCAPE_CHARACTER), + ("08006", SqlState::CONNECTION_FAILURE), + ("22021", SqlState::CHARACTER_NOT_IN_REPERTOIRE), ("21000", SqlState::CARDINALITY_VIOLATION), - ("0A000", SqlState::FEATURE_NOT_SUPPORTED), - ("HV014", SqlState::FDW_TOO_MANY_HANDLES), - ("08004", SqlState::SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION), - ("38001", SqlState::E_R_E_CONTAINING_SQL_NOT_PERMITTED), - ("01003", SqlState::WARNING_NULL_VALUE_ELIMINATED_IN_SET_FUNCTION), - ("08007", SqlState::TRANSACTION_RESOLUTION_UNKNOWN), - ("HV00D", SqlState::FDW_INVALID_OPTION_NAME), + ("42803", SqlState::GROUPING_ERROR), + ("00000", SqlState::SUCCESSFUL_COMPLETION), + ("42P16", SqlState::INVALID_TABLE_DEFINITION), ("38002", SqlState::E_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED), + ("57P03", SqlState::CANNOT_CONNECT_NOW), + ("01004", SqlState::WARNING_STRING_DATA_RIGHT_TRUNCATION), ("HV00K", SqlState::FDW_REPLY_HANDLE), - ("23P01", SqlState::EXCLUSION_VIOLATION), - ("42P04", SqlState::DUPLICATE_DATABASE), - ("22025", SqlState::INVALID_ESCAPE_SEQUENCE), - ("HV007", SqlState::FDW_INVALID_COLUMN_NAME), - ("34000", SqlState::INVALID_CURSOR_NAME), - ("HV00L", SqlState::FDW_UNABLE_TO_CREATE_EXECUTION), - ("HV009", SqlState::FDW_INVALID_USE_OF_NULL_POINTER), - ("38000", SqlState::EXTERNAL_ROUTINE_EXCEPTION), - ("2B000", SqlState::DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST), - ("00000", SqlState::SUCCESSFUL_COMPLETION), - ("58000", SqlState::SYSTEM_ERROR), - ("2201E", SqlState::INVALID_ARGUMENT_FOR_LOG), - ("HV024", SqlState::FDW_INVALID_ATTRIBUTE_VALUE), + ("42P06", SqlState::DUPLICATE_SCHEMA), + ("54000", SqlState::PROGRAM_LIMIT_EXCEEDED), + ("2200S", SqlState::INVALID_XML_COMMENT), + ("42000", SqlState::SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION), + ("42P03", SqlState::DUPLICATE_CURSOR), + ("HV002", SqlState::FDW_DYNAMIC_PARAMETER_VALUE_NEEDED), + ("2202H", SqlState::INVALID_TABLESAMPLE_ARGUMENT), + ("08001", SqlState::SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION), + ("0L000", SqlState::INVALID_GRANTOR), ("2200L", SqlState::NOT_AN_XML_DOCUMENT), - ("2203B", SqlState::SQL_JSON_NUMBER_NOT_FOUND), - ("42846", SqlState::CANNOT_COERCE), - ("22035", SqlState::NO_SQL_JSON_ITEM), - ("HV005", SqlState::FDW_COLUMN_NAME_NOT_FOUND), - ("20000", SqlState::CASE_NOT_FOUND), - ("40001", SqlState::T_R_SERIALIZATION_FAILURE), + ("HV006", SqlState::FDW_INVALID_DATA_TYPE_DESCRIPTORS), + ("55000", SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE), + ("58P01", SqlState::UNDEFINED_FILE), + ("0B000", SqlState::INVALID_TRANSACTION_INITIATION), ("22000", SqlState::DATA_EXCEPTION), + ("HV00R", SqlState::FDW_TABLE_NOT_FOUND), + ("2F002", SqlState::S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED), + ("01007", SqlState::WARNING_PRIVILEGE_NOT_GRANTED), + ("42P19", SqlState::INVALID_RECURSION), + ("22016", SqlState::INVALID_ARGUMENT_FOR_NTH_VALUE), + ("42702", SqlState::AMBIGUOUS_COLUMN), + ("25005", SqlState::NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION), + ("22004", SqlState::NULL_VALUE_NOT_ALLOWED), + ("42P05", SqlState::DUPLICATE_PSTATEMENT), + ("39001", SqlState::E_R_I_E_INVALID_SQLSTATE_RETURNED), ("22038", SqlState::SINGLETON_SQL_JSON_ITEM_REQUIRED), - ("42P14", SqlState::INVALID_PSTATEMENT_DEFINITION), + ("22008", SqlState::DATETIME_FIELD_OVERFLOW), + ("38003", SqlState::E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), + ("53000", SqlState::INSUFFICIENT_RESOURCES), + ("3B001", SqlState::S_E_INVALID_SPECIFICATION), + ("28000", SqlState::INVALID_AUTHORIZATION_SPECIFICATION), + ("P0000", SqlState::PLPGSQL_ERROR), + ("38000", SqlState::EXTERNAL_ROUTINE_EXCEPTION), + ("22019", SqlState::INVALID_ESCAPE_CHARACTER), + ("22015", SqlState::INTERVAL_FIELD_OVERFLOW), + ("42710", SqlState::DUPLICATE_OBJECT), + ("2200M", SqlState::INVALID_XML_DOCUMENT), + ("HV000", SqlState::FDW_ERROR), + ("22P05", SqlState::UNTRANSLATABLE_CHARACTER), + ("0100C", SqlState::WARNING_DYNAMIC_RESULT_SETS_RETURNED), + ("55P02", SqlState::CANT_CHANGE_RUNTIME_PARAM), + ("01003", SqlState::WARNING_NULL_VALUE_ELIMINATED_IN_SET_FUNCTION), + ("2200N", SqlState::INVALID_XML_CONTENT), + ("2F000", SqlState::SQL_ROUTINE_EXCEPTION), + ("08007", SqlState::TRANSACTION_RESOLUTION_UNKNOWN), + ("2200B", SqlState::ESCAPE_CHARACTER_CONFLICT), + ("22P03", SqlState::INVALID_BINARY_REPRESENTATION), + ("42P09", SqlState::AMBIGUOUS_ALIAS), + ("39004", SqlState::E_R_I_E_NULL_VALUE_NOT_ALLOWED), + ("23502", SqlState::NOT_NULL_VIOLATION), + ("2203D", SqlState::TOO_MANY_JSON_ARRAY_ELEMENTS), + ("42P15", SqlState::INVALID_SCHEMA_DEFINITION), + ("08004", SqlState::SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION), + ("HV00N", SqlState::FDW_UNABLE_TO_ESTABLISH_CONNECTION), + ("0A000", SqlState::FEATURE_NOT_SUPPORTED), + ("57014", SqlState::QUERY_CANCELED), + ("22033", SqlState::INVALID_SQL_JSON_SUBSCRIPT), + ("0F001", SqlState::L_E_INVALID_SPECIFICATION), + ("HV00A", SqlState::FDW_INVALID_STRING_FORMAT), ("39P02", SqlState::E_R_I_E_SRF_PROTOCOL_VIOLATED), + ("42701", SqlState::DUPLICATE_COLUMN), + ("42611", SqlState::INVALID_COLUMN_DEFINITION), + ("HV001", SqlState::FDW_OUT_OF_MEMORY), + ("HV091", SqlState::FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER), + ("23P01", SqlState::EXCLUSION_VIOLATION), + ("F0001", SqlState::LOCK_FILE_EXISTS), + ("42501", SqlState::INSUFFICIENT_PRIVILEGE), + ("22026", SqlState::STRING_DATA_LENGTH_MISMATCH), + ("54023", SqlState::TOO_MANY_ARGUMENTS), ("01008", SqlState::WARNING_IMPLICIT_ZERO_BIT_PADDING), - ("42P15", SqlState::INVALID_SCHEMA_DEFINITION), - ("55006", SqlState::OBJECT_IN_USE), - ("2203F", SqlState::SQL_JSON_SCALAR_REQUIRED), - ("22014", SqlState::INVALID_ARGUMENT_FOR_NTILE), + ("42P04", SqlState::DUPLICATE_DATABASE), + ("22027", SqlState::TRIM_ERROR), + ("53300", SqlState::TOO_MANY_CONNECTIONS), + ("0Z002", SqlState::STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER), + ("42P14", SqlState::INVALID_PSTATEMENT_DEFINITION), + ("P0001", SqlState::RAISE_EXCEPTION), + ("HV014", SqlState::FDW_TOO_MANY_HANDLES), + ("40002", SqlState::T_R_INTEGRITY_CONSTRAINT_VIOLATION), + ("3D000", SqlState::INVALID_CATALOG_NAME), ("03000", SqlState::SQL_STATEMENT_NOT_YET_COMPLETE), - ("22008", SqlState::DATETIME_FIELD_OVERFLOW), - ("08006", SqlState::CONNECTION_FAILURE), - ("42P01", SqlState::UNDEFINED_TABLE), - ("40P01", SqlState::T_R_DEADLOCK_DETECTED), - ("0L000", SqlState::INVALID_GRANTOR), + ("22024", SqlState::UNTERMINATED_C_STRING), + ("42P13", SqlState::INVALID_FUNCTION_DEFINITION), + ("08000", SqlState::CONNECTION_EXCEPTION), + ("25007", SqlState::SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED), + ("40001", SqlState::T_R_SERIALIZATION_FAILURE), + ("25001", SqlState::ACTIVE_SQL_TRANSACTION), + ("HV00Q", SqlState::FDW_SCHEMA_NOT_FOUND), + ("22P04", SqlState::BAD_COPY_FILE_FORMAT), + ("XX001", SqlState::DATA_CORRUPTED), + ("23503", SqlState::FOREIGN_KEY_VIOLATION), + ("23514", SqlState::CHECK_VIOLATION), + ("42809", SqlState::WRONG_OBJECT_TYPE), + ("2200F", SqlState::ZERO_LENGTH_CHARACTER_STRING), + ("2BP01", SqlState::DEPENDENT_OBJECTS_STILL_EXIST), + ("25008", SqlState::HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL), + ("55P03", SqlState::LOCK_NOT_AVAILABLE), + ("42P22", SqlState::INDETERMINATE_COLLATION), + ("HV00D", SqlState::FDW_INVALID_OPTION_NAME), + ("42P17", SqlState::INVALID_OBJECT_DEFINITION), + ("23001", SqlState::RESTRICT_VIOLATION), + ("22P06", SqlState::NONSTANDARD_USE_OF_ESCAPE_CHARACTER), + ("22031", SqlState::INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION), + ("2200D", SqlState::INVALID_ESCAPE_OCTET), + ("0Z000", SqlState::DIAGNOSTICS_EXCEPTION), + ("HV024", SqlState::FDW_INVALID_ATTRIBUTE_VALUE), ("22005", SqlState::ERROR_IN_ASSIGNMENT), - ("42622", SqlState::NAME_TOO_LONG), - ("57P04", SqlState::DATABASE_DROPPED), - ("42803", SqlState::GROUPING_ERROR), - ("22P01", SqlState::FLOATING_POINT_EXCEPTION), - ("42P18", SqlState::INDETERMINATE_DATATYPE), + ("58P02", SqlState::DUPLICATE_FILE), + ("HV00P", SqlState::FDW_NO_SCHEMAS), + ("42P10", SqlState::INVALID_COLUMN_REFERENCE), + ("42P20", SqlState::WINDOWING_ERROR), + ("25000", SqlState::INVALID_TRANSACTION_STATE), ("38004", SqlState::E_R_E_READING_SQL_DATA_NOT_PERMITTED), - ("39P03", SqlState::E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED), - ("2200N", SqlState::INVALID_XML_CONTENT), - ("57P02", SqlState::CRASH_SHUTDOWN), + ("01P01", SqlState::WARNING_DEPRECATED_FEATURE), + ("40000", SqlState::TRANSACTION_ROLLBACK), + ("58030", SqlState::IO_ERROR), + ("26000", SqlState::INVALID_SQL_STATEMENT_NAME), + ("22007", SqlState::INVALID_DATETIME_FORMAT), ("23000", SqlState::INTEGRITY_CONSTRAINT_VIOLATION), - ("0F000", SqlState::LOCATOR_EXCEPTION), - ("08000", SqlState::CONNECTION_EXCEPTION), - ("2202E", SqlState::ARRAY_ELEMENT_ERROR), - ("22024", SqlState::UNTERMINATED_C_STRING), + ("0P000", SqlState::INVALID_ROLE_SPECIFICATION), + ("22014", SqlState::INVALID_ARGUMENT_FOR_NTILE), + ("P0002", SqlState::NO_DATA_FOUND), + ("39P03", SqlState::E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED), + ("39000", SqlState::EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), + ("42P11", SqlState::INVALID_CURSOR_DEFINITION), + ("HV010", SqlState::FDW_FUNCTION_SEQUENCE_ERROR), + ("22002", SqlState::NULL_VALUE_NO_INDICATOR_PARAMETER), ("08P01", SqlState::PROTOCOL_VIOLATION), - ("22023", SqlState::INVALID_PARAMETER_VALUE), - ("22031", SqlState::INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION), - ("HV00P", SqlState::FDW_NO_SCHEMAS), - ("23514", SqlState::CHECK_VIOLATION), - ("HV00Q", SqlState::FDW_SCHEMA_NOT_FOUND), - ("22P05", SqlState::UNTRANSLATABLE_CHARACTER), - ("53400", SqlState::CONFIGURATION_LIMIT_EXCEEDED), - ("3F000", SqlState::INVALID_SCHEMA_NAME), - ("22037", SqlState::NON_UNIQUE_KEYS_IN_A_JSON_OBJECT), - ("22004", SqlState::NULL_VALUE_NOT_ALLOWED), - ("2200B", SqlState::ESCAPE_CHARACTER_CONFLICT), - ("HV090", SqlState::FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH), - ("HV00R", SqlState::FDW_TABLE_NOT_FOUND), ("42723", SqlState::DUPLICATE_FUNCTION), - ("22009", SqlState::INVALID_TIME_ZONE_DISPLACEMENT_VALUE), - ("HV00N", SqlState::FDW_UNABLE_TO_ESTABLISH_CONNECTION), - ("3B000", SqlState::SAVEPOINT_EXCEPTION), - ("22018", SqlState::INVALID_CHARACTER_VALUE_FOR_CAST), - ("HV004", SqlState::FDW_INVALID_DATA_TYPE), - ("08003", SqlState::CONNECTION_DOES_NOT_EXIST), - ("42P02", SqlState::UNDEFINED_PARAMETER), - ("23001", SqlState::RESTRICT_VIOLATION), - ("HV00C", SqlState::FDW_INVALID_OPTION_INDEX), - ("HV010", SqlState::FDW_FUNCTION_SEQUENCE_ERROR), - ("28P01", SqlState::INVALID_PASSWORD), - ("55000", SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE), - ("2201X", SqlState::INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE), - ("P0001", SqlState::RAISE_EXCEPTION), - ("25000", SqlState::INVALID_TRANSACTION_STATE), - ("42704", SqlState::UNDEFINED_OBJECT), - ("22022", SqlState::INDICATOR_OVERFLOW), - ("09000", SqlState::TRIGGERED_ACTION_EXCEPTION), - ("22026", SqlState::STRING_DATA_LENGTH_MISMATCH), - ("01007", SqlState::WARNING_PRIVILEGE_NOT_GRANTED), - ("2200H", SqlState::SEQUENCE_GENERATOR_LIMIT_EXCEEDED), - ("25007", SqlState::SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED), - ("42701", SqlState::DUPLICATE_COLUMN), - ("42P08", SqlState::AMBIGUOUS_PARAMETER), - ("2201B", SqlState::INVALID_REGULAR_EXPRESSION), - ("22036", SqlState::NON_NUMERIC_SQL_JSON_ITEM), - ("22011", SqlState::SUBSTRING_ERROR), - ("0LP01", SqlState::INVALID_GRANT_OPERATION), + ("40003", SqlState::T_R_STATEMENT_COMPLETION_UNKNOWN), + ("25003", SqlState::INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION), + ("02001", SqlState::NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED), + ("42804", SqlState::DATATYPE_MISMATCH), ]), }; From 8f7481a86cb4c4cf5658a0c8ba2cbe3cd7cb6d54 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 23 Jun 2021 20:02:51 -0400 Subject: [PATCH 119/420] fix clippy --- postgres-protocol/src/types/test.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/postgres-protocol/src/types/test.rs b/postgres-protocol/src/types/test.rs index 8796ab31b..09edeee3a 100644 --- a/postgres-protocol/src/types/test.rs +++ b/postgres-protocol/src/types/test.rs @@ -6,6 +6,7 @@ use super::*; use crate::IsNull; #[test] +#[allow(clippy::bool_assert_comparison)] fn bool() { let mut buf = BytesMut::new(); bool_to_sql(true, &mut buf); @@ -113,7 +114,7 @@ fn array() { .unwrap(); let array = array_from_sql(&buf).unwrap(); - assert_eq!(array.has_nulls(), true); + assert!(array.has_nulls()); assert_eq!(array.element_type(), 10); assert_eq!(array.dimensions().collect::>().unwrap(), dimensions); assert_eq!(array.values().collect::>().unwrap(), values); @@ -150,7 +151,7 @@ fn non_null_array() { .unwrap(); let array = array_from_sql(&buf).unwrap(); - assert_eq!(array.has_nulls(), false); + assert!(array.has_nulls()); assert_eq!(array.element_type(), 10); assert_eq!(array.dimensions().collect::>().unwrap(), dimensions); assert_eq!(array.values().collect::>().unwrap(), values); From 3eb5a4dab94e95df071949a31e7765031511c8cf Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 23 Jun 2021 20:15:57 -0400 Subject: [PATCH 120/420] actually fix clippy --- postgres-protocol/src/types/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres-protocol/src/types/test.rs b/postgres-protocol/src/types/test.rs index 09edeee3a..7c20cf3ed 100644 --- a/postgres-protocol/src/types/test.rs +++ b/postgres-protocol/src/types/test.rs @@ -151,7 +151,7 @@ fn non_null_array() { .unwrap(); let array = array_from_sql(&buf).unwrap(); - assert!(array.has_nulls()); + assert!(!array.has_nulls()); assert_eq!(array.element_type(), 10); assert_eq!(array.dimensions().collect::>().unwrap(), dimensions); assert_eq!(array.values().collect::>().unwrap(), values); From 3b7b8000ce2d135883c248dd11d02e376a4aa678 Mon Sep 17 00:00:00 2001 From: JR Smith Date: Thu, 1 Jul 2021 16:04:19 -0400 Subject: [PATCH 121/420] Made requirement of setting feature flags to access derive macros more explicit in the documentation. --- postgres-types/src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index ed6f75cf5..1973f3d0e 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -6,7 +6,12 @@ //! # Derive //! //! If the `derive` cargo feature is enabled, you can derive `ToSql` and `FromSql` implementations for custom Postgres -//! types. +//! types. Explicitly, modify your `Cargo.toml` file to include the following: +//! +//! ```toml +//! [dependencies] +//! postgres-types = { version = "0.X.X", features = ["derive"] } +//! ``` //! //! ## Enums //! From 6c1542f634ae0d7733811024cd63835045f75784 Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Tue, 13 Jul 2021 11:21:11 +0200 Subject: [PATCH 122/420] Add `FromSql` and `ToSql` impls for arrays (guarded behind feature) This is feature-gated because those impls require Rust 1.51. --- postgres-types/Cargo.toml | 2 + postgres-types/src/lib.rs | 66 ++++++++++++++++++++++++-- postgres/Cargo.toml | 1 + tokio-postgres/Cargo.toml | 1 + tokio-postgres/tests/test/types/mod.rs | 14 +++++- 5 files changed, 79 insertions(+), 5 deletions(-) diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index b258cee12..4fd69f613 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -12,6 +12,7 @@ categories = ["database"] [features] derive = ["postgres-derive"] +array-impls = ["array-init"] with-bit-vec-0_6 = ["bit-vec-06"] with-chrono-0_4 = ["chrono-04"] with-eui48-0_4 = ["eui48-04"] @@ -28,6 +29,7 @@ fallible-iterator = "0.2" postgres-protocol = { version = "0.6.1", path = "../postgres-protocol" } postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-derive" } +array-init = { version = "2", optional = true } bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } chrono-04 = { version = "0.4.16", package = "chrono", default-features = false, features = ["clock"], optional = true } eui48-04 = { version = "0.4", package = "eui48", optional = true } diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 1973f3d0e..4c559b95a 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -428,8 +428,10 @@ impl WrongType { /// /// # Arrays /// -/// `FromSql` is implemented for `Vec` where `T` implements `FromSql`, and -/// corresponds to one-dimensional Postgres arrays. +/// `FromSql` is implemented for `Vec` and `[T; N]` where `T` implements +/// `FromSql`, and corresponds to one-dimensional Postgres arrays. **Note:** +/// the impl for arrays only exist when the Cargo feature `array-impls` is +/// enabled. pub trait FromSql<'a>: Sized { /// Creates a new value of this type from a buffer of data of the specified /// Postgres `Type` in its binary format. @@ -513,6 +515,47 @@ impl<'a, T: FromSql<'a>> FromSql<'a> for Vec { } } +#[cfg(feature = "array-impls")] +impl<'a, T: FromSql<'a>, const N: usize> FromSql<'a> for [T; N] { + fn from_sql(ty: &Type, raw: &'a [u8]) -> Result> { + let member_type = match *ty.kind() { + Kind::Array(ref member) => member, + _ => panic!("expected array type"), + }; + + let array = types::array_from_sql(raw)?; + if array.dimensions().count()? > 1 { + return Err("array contains too many dimensions".into()); + } + + let mut values = array.values(); + let out = array_init::try_array_init(|i| { + let v = values + .next()? + .ok_or_else(|| -> Box { + format!("too few elements in array (expected {}, got {})", N, i).into() + })?; + T::from_sql_nullable(member_type, v) + })?; + if values.next()?.is_some() { + return Err(format!( + "excess elements in array (expected {}, got more than that)", + N, + ) + .into()); + } + + Ok(out) + } + + fn accepts(ty: &Type) -> bool { + match *ty.kind() { + Kind::Array(ref inner) => T::accepts(inner), + _ => false, + } + } +} + impl<'a> FromSql<'a> for Vec { fn from_sql(_: &Type, raw: &'a [u8]) -> Result, Box> { Ok(types::bytea_from_sql(raw).to_owned()) @@ -691,8 +734,10 @@ pub enum IsNull { /// /// # Arrays /// -/// `ToSql` is implemented for `Vec` and `&[T]` where `T` implements `ToSql`, -/// and corresponds to one-dimensional Postgres arrays with an index offset of 1. +/// `ToSql` is implemented for `Vec`, `&[T]` and `[T; N]` where `T` +/// implements `ToSql`, and corresponds to one-dimensional Postgres arrays with +/// an index offset of 1. **Note:** the impl for arrays only exist when the +/// Cargo feature `array-impls` is enabled. pub trait ToSql: fmt::Debug { /// Converts the value of `self` into the binary format of the specified /// Postgres `Type`, appending it to `out`. @@ -808,6 +853,19 @@ impl<'a> ToSql for &'a [u8] { to_sql_checked!(); } +#[cfg(feature = "array-impls")] +impl ToSql for [T; N] { + fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { + <&[T] as ToSql>::to_sql(&&self[..], ty, w) + } + + fn accepts(ty: &Type) -> bool { + <&[T] as ToSql>::accepts(ty) + } + + to_sql_checked!(); +} + impl ToSql for Vec { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { <&[T] as ToSql>::to_sql(&&**self, ty, w) diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index c7c0746f0..ca1d0b232 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -21,6 +21,7 @@ all-features = true circle-ci = { repository = "sfackler/rust-postgres" } [features] +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-eui48-0_4 = ["tokio-postgres/with-eui48-0_4"] diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 3a1537a87..edffde49a 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -27,6 +27,7 @@ circle-ci = { repository = "sfackler/rust-postgres" } default = ["runtime"] 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-eui48-0_4 = ["postgres-types/with-eui48-0_4"] diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index 85eed0e27..54a111b3a 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -350,7 +350,7 @@ async fn test_hstore_params() { } #[tokio::test] -async fn test_array_params() { +async fn test_array_vec_params() { test_type( "integer[]", &[ @@ -363,6 +363,18 @@ async fn test_array_params() { .await; } +#[cfg(feature = "array-impls")] +#[tokio::test] +async fn test_array_array_params() { + test_type("integer[]", &[(Some([1i32, 2i32]), "ARRAY[1,2]")]).await; + test_type("text[]", &[(Some(["peter".to_string()]), "ARRAY['peter']")]).await; + test_type( + "integer[]", + &[(Some([] as [i32; 0]), "ARRAY[]"), (None, "NULL")], + ) + .await; +} + #[allow(clippy::eq_op)] async fn test_nan_param(sql_type: &str) where From 06952e2bb09bdcc404b82f24774c5ada756a360f Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Tue, 13 Jul 2021 14:38:11 +0200 Subject: [PATCH 123/420] Use Rust 1.51 in CI We needed to bump the version because the `array-impls` feature requires const generics. --- .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 4a95dbe0c..8b3a3420d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,7 @@ jobs: - uses: actions/checkout@v2 - uses: sfackler/actions/rustup@master with: - version: 1.46.0 + version: 1.51.0 - run: echo "::set-output name=version::$(rustc --version)" id: rust-version - uses: actions/cache@v1 From 24928ebce3b7b5480d33a0593b8d89c1c4a11081 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Jul 2021 13:10:25 +0000 Subject: [PATCH 124/420] Update env_logger requirement from 0.8 to 0.9 Updates the requirements on [env_logger](https://github.com/env-logger-rs/env_logger) to permit the latest version. - [Release notes](https://github.com/env-logger-rs/env_logger/releases) - [Changelog](https://github.com/env-logger-rs/env_logger/blob/main/CHANGELOG.md) - [Commits](https://github.com/env-logger-rs/env_logger/compare/v0.8.0...v0.9.0) --- updated-dependencies: - dependency-name: env_logger dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- tokio-postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index edffde49a..db3a65f32 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -57,7 +57,7 @@ tokio-util = { version = "0.6", features = ["codec"] } [dev-dependencies] tokio = { version = "1.0", features = ["full"] } -env_logger = "0.8" +env_logger = "0.9" criterion = "0.3" bit-vec-06 = { version = "0.6", package = "bit-vec" } From da4e323578e868ff720d409e7c63dc41fa00bd3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Bizjak?= Date: Sun, 25 Jul 2021 22:02:28 +0200 Subject: [PATCH 125/420] Implement BorrowToSql for an additional type. Closes #811. --- postgres-types/src/lib.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 4c559b95a..59ec4f811 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -1042,6 +1042,19 @@ impl BorrowToSql for &dyn ToSql { } } +impl sealed::Sealed for &(dyn ToSql + Sync) {} + +/// In async contexts it is sometimes necessary to have the additional +/// Sync requirement on parameters for queries since this enables the +/// resulting Futures to be Send, hence usable in, e.g., tokio::spawn. +/// This instance is provided for those cases. +impl BorrowToSql for &(dyn ToSql + Sync) { + #[inline] + fn borrow_to_sql(&self) -> &dyn ToSql { + *self + } +} + impl sealed::Sealed for T where T: ToSql {} impl BorrowToSql for T From be0c85ac0b985986b7ffdf8e68cc91294481c2e2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 10 Aug 2021 20:30:27 -0400 Subject: [PATCH 126/420] Update phf --- codegen/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- tokio-postgres/src/error/sqlstate.rs | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index fc02751cf..14bebccf2 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Steven Fackler "] [dependencies] -phf_codegen = "0.9" +phf_codegen = "0.10" regex = "1.0" marksman_escape = "0.1" linked-hash-map = "0.5" diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index db3a65f32..1bedf6b57 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -48,7 +48,7 @@ log = "0.4" parking_lot = "0.11" percent-encoding = "2.0" pin-project-lite = "0.2" -phf = "0.9" +phf = "0.10" postgres-protocol = { version = "0.6.1", path = "../postgres-protocol" } postgres-types = { version = "0.2.1", path = "../postgres-types" } socket2 = "0.4" diff --git a/tokio-postgres/src/error/sqlstate.rs b/tokio-postgres/src/error/sqlstate.rs index 1996d9b13..71648a948 100644 --- a/tokio-postgres/src/error/sqlstate.rs +++ b/tokio-postgres/src/error/sqlstate.rs @@ -1341,7 +1341,7 @@ enum Inner { static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ::phf::Map { key: 12913932095322966823, - disps: ::phf::Slice::Static(&[ + disps: &[ (0, 12), (0, 18), (0, 25), @@ -1394,8 +1394,8 @@ static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = (0, 242), (0, 72), (16, 53), - ]), - entries: ::phf::Slice::Static(&[ + ], + entries: &[ ("22034", SqlState::MORE_THAN_ONE_SQL_JSON_ITEM), ("40P01", SqlState::T_R_DEADLOCK_DETECTED), ("42703", SqlState::UNDEFINED_COLUMN), @@ -1654,5 +1654,5 @@ static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ("25003", SqlState::INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION), ("02001", SqlState::NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED), ("42804", SqlState::DATATYPE_MISMATCH), - ]), + ], }; From a8a35eb6db62b878b168c5c53110be8d6a393b4c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 10 Aug 2021 21:07:20 -0400 Subject: [PATCH 127/420] fix clippy --- postgres-derive/src/tosql.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres-derive/src/tosql.rs b/postgres-derive/src/tosql.rs index a1c87b0ff..1808e787d 100644 --- a/postgres-derive/src/tosql.rs +++ b/postgres-derive/src/tosql.rs @@ -30,7 +30,7 @@ pub fn expand_derive_tosql(input: DeriveInput) -> Result { .. }) if fields.unnamed.len() == 1 => { let field = fields.unnamed.first().unwrap(); - (accepts::domain_body(&name, &field), domain_body()) + (accepts::domain_body(&name, field), domain_body()) } Data::Struct(DataStruct { fields: Fields::Named(ref fields), From 3e4be865318ddd4a6b4493d689703db32ca3d184 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 10 Aug 2021 21:17:50 -0400 Subject: [PATCH 128/420] more clippy --- postgres-types/src/lib.rs | 2 +- tokio-postgres/src/config.rs | 8 ++++---- tokio-postgres/src/prepare.rs | 8 ++++---- tokio-postgres/src/transaction.rs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 59ec4f811..4dd87c71c 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -909,7 +909,7 @@ impl<'a> ToSql for &'a str { impl<'a> ToSql for Cow<'a, str> { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { - <&str as ToSql>::to_sql(&&self.as_ref(), ty, w) + <&str as ToSql>::to_sql(&self.as_ref(), ty, w) } fn accepts(ty: &Type) -> bool { diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 111487173..eb4e5bdc5 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -390,19 +390,19 @@ impl Config { fn param(&mut self, key: &str, value: &str) -> Result<(), Error> { match key { "user" => { - self.user(&value); + self.user(value); } "password" => { self.password(value); } "dbname" => { - self.dbname(&value); + self.dbname(value); } "options" => { - self.options(&value); + self.options(value); } "application_name" => { - self.application_name(&value); + self.application_name(value); } "sslmode" => { let mode = match value { diff --git a/tokio-postgres/src/prepare.rs b/tokio-postgres/src/prepare.rs index 49397debf..7a6163415 100644 --- a/tokio-postgres/src/prepare.rs +++ b/tokio-postgres/src/prepare.rs @@ -86,7 +86,7 @@ pub async fn prepare( let mut parameters = vec![]; let mut it = parameter_description.parameters(); while let Some(oid) = it.next().map_err(Error::parse)? { - let type_ = get_type(&client, oid).await?; + let type_ = get_type(client, oid).await?; parameters.push(type_); } @@ -94,13 +94,13 @@ pub async fn prepare( if let Some(row_description) = row_description { let mut it = row_description.fields(); while let Some(field) = it.next().map_err(Error::parse)? { - let type_ = get_type(&client, field.type_oid()).await?; + let type_ = get_type(client, field.type_oid()).await?; let column = Column::new(field.name().to_string(), type_); columns.push(column); } } - Ok(Statement::new(&client, name, parameters, columns)) + Ok(Statement::new(client, name, parameters, columns)) } fn prepare_rec<'a>( @@ -120,7 +120,7 @@ fn encode(client: &InnerClient, name: &str, query: &str, types: &[Type]) -> Resu client.with_buf(|buf| { frontend::parse(name, query, types.iter().map(Type::oid), buf).map_err(Error::encode)?; - frontend::describe(b'S', &name, buf).map_err(Error::encode)?; + frontend::describe(b'S', name, buf).map_err(Error::encode)?; frontend::sync(buf); Ok(buf.split().freeze()) }) diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index a1aa7611f..b72b119bf 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -201,7 +201,7 @@ impl<'a> Transaction<'a> { I: IntoIterator, I::IntoIter: ExactSizeIterator, { - let statement = statement.__convert().into_statement(&self.client).await?; + let statement = statement.__convert().into_statement(self.client).await?; bind::bind(self.client.inner(), statement, params).await } From be0d71fad51b9ea070493ed44a2ab15557635b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Thu, 23 Sep 2021 19:28:02 +0300 Subject: [PATCH 129/420] Add support for time 0.3 --- postgres-types/Cargo.toml | 2 + postgres-types/src/lib.rs | 2 + postgres-types/src/time_03.rs | 108 +++++++++++++++ postgres/Cargo.toml | 1 + postgres/src/lib.rs | 3 +- tokio-postgres/Cargo.toml | 3 +- tokio-postgres/src/lib.rs | 3 +- tokio-postgres/tests/test/types/mod.rs | 2 + tokio-postgres/tests/test/types/time_03.rs | 149 +++++++++++++++++++++ 9 files changed, 270 insertions(+), 3 deletions(-) create mode 100644 postgres-types/src/time_03.rs create mode 100644 tokio-postgres/tests/test/types/time_03.rs diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 4fd69f613..8fc6ed107 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -22,6 +22,7 @@ with-geo-types-0_7 = ["geo-types-0_7"] with-serde_json-1 = ["serde-1", "serde_json-1"] with-uuid-0_8 = ["uuid-08"] with-time-0_2 = ["time-02"] +with-time-0_3 = ["time-03"] [dependencies] bytes = "1.0" @@ -40,3 +41,4 @@ serde-1 = { version = "1.0", package = "serde", optional = true } serde_json-1 = { version = "1.0", package = "serde_json", optional = true } uuid-08 = { version = "0.8", package = "uuid", optional = true } time-02 = { version = "0.2", package = "time", optional = true } +time-03 = { version = "0.3", package = "time", default-features = false, optional = true } diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 4dd87c71c..2a953db2f 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -209,6 +209,8 @@ mod geo_types_07; mod serde_json_1; #[cfg(feature = "with-time-0_2")] mod time_02; +#[cfg(feature = "with-time-0_3")] +mod time_03; #[cfg(feature = "with-uuid-0_8")] mod uuid_08; diff --git a/postgres-types/src/time_03.rs b/postgres-types/src/time_03.rs new file mode 100644 index 000000000..f136fab7c --- /dev/null +++ b/postgres-types/src/time_03.rs @@ -0,0 +1,108 @@ +use bytes::BytesMut; +use postgres_protocol::types; +use std::convert::TryFrom; +use std::error::Error; +use time_03::{Date, Duration, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset}; + +use crate::{FromSql, IsNull, ToSql, Type}; + +fn base() -> PrimitiveDateTime { + PrimitiveDateTime::new(Date::from_ordinal_date(2000, 1).unwrap(), Time::MIDNIGHT) +} + +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)) + } + + accepts!(TIMESTAMP); +} + +impl ToSql for PrimitiveDateTime { + fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { + let time = match i64::try_from((*self - base()).whole_microseconds()) { + Ok(time) => time, + Err(_) => return Err("value too large to transmit".into()), + }; + types::timestamp_to_sql(time, w); + Ok(IsNull::No) + } + + accepts!(TIMESTAMP); + to_sql_checked!(); +} + +impl<'a> FromSql<'a> for OffsetDateTime { + fn from_sql(type_: &Type, raw: &[u8]) -> Result> { + let primitive = PrimitiveDateTime::from_sql(type_, raw)?; + Ok(primitive.assume_utc()) + } + + accepts!(TIMESTAMPTZ); +} + +impl ToSql for OffsetDateTime { + fn to_sql( + &self, + type_: &Type, + w: &mut BytesMut, + ) -> Result> { + let utc_datetime = self.to_offset(UtcOffset::UTC); + let date = utc_datetime.date(); + let time = utc_datetime.time(); + let primitive = PrimitiveDateTime::new(date, time); + primitive.to_sql(type_, w) + } + + accepts!(TIMESTAMPTZ); + to_sql_checked!(); +} + +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))) + } + + accepts!(DATE); +} + +impl ToSql for Date { + fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { + let jd = (*self - base().date()).whole_days(); + if jd > i64::from(i32::max_value()) || jd < i64::from(i32::min_value()) { + return Err("value too large to transmit".into()); + } + + types::date_to_sql(jd as i32, w); + Ok(IsNull::No) + } + + accepts!(DATE); + to_sql_checked!(); +} + +impl<'a> FromSql<'a> for Time { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let usec = types::time_from_sql(raw)?; + Ok(Time::MIDNIGHT + Duration::microseconds(usec)) + } + + accepts!(TIME); +} + +impl ToSql for Time { + fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { + let delta = *self - Time::MIDNIGHT; + let time = match i64::try_from(delta.whole_microseconds()) { + Ok(time) => time, + Err(_) => return Err("value too large to transmit".into()), + }; + types::time_to_sql(time, w); + Ok(IsNull::No) + } + + accepts!(TIME); + to_sql_checked!(); +} diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index ca1d0b232..3d1c20234 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -31,6 +31,7 @@ with-geo-types-0_7 = ["tokio-postgres/with-geo-types-0_7"] with-serde_json-1 = ["tokio-postgres/with-serde_json-1"] with-uuid-0_8 = ["tokio-postgres/with-uuid-0_8"] with-time-0_2 = ["tokio-postgres/with-time-0_2"] +with-time-0_3 = ["tokio-postgres/with-time-0_3"] [dependencies] bytes = "1.0" diff --git a/postgres/src/lib.rs b/postgres/src/lib.rs index 7d96bfd9f..a599532e4 100644 --- a/postgres/src/lib.rs +++ b/postgres/src/lib.rs @@ -61,7 +61,8 @@ //! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | -//! | `with-time-0_2` | Enable support for the `time` crate. | [time](https://crates.io/crates/time) 0.2 | no | +//! | `with-time-0_2` | Enable support for the 0.2 version of the `time` crate. | [time](https://crates.io/crates/time/0.2.0) 0.2 | no | +//! | `with-time-0_3` | Enable support for the 0.3 version of the `time` crate. | [time](https://crates.io/crates/time/0.3.0) 0.3 | no | #![warn(clippy::all, rust_2018_idioms, missing_docs)] pub use fallible_iterator; diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 1bedf6b57..d35a323a1 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -37,6 +37,7 @@ with-geo-types-0_7 = ["postgres-types/with-geo-types-0_7"] with-serde_json-1 = ["postgres-types/with-serde_json-1"] with-uuid-0_8 = ["postgres-types/with-uuid-0_8"] with-time-0_2 = ["postgres-types/with-time-0_2"] +with-time-0_3 = ["postgres-types/with-time-0_3"] [dependencies] async-trait = "0.1" @@ -70,4 +71,4 @@ serde-1 = { version = "1.0", package = "serde" } serde_json-1 = { version = "1.0", package = "serde_json" } uuid-08 = { version = "0.8", package = "uuid" } time-02 = { version = "0.2", package = "time" } - +time-03 = { version = "0.3", package = "time", features = ["parsing"] } diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 6dd0b0151..e9516e0b3 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -112,7 +112,8 @@ //! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | -//! | `with-time-0_2` | Enable support for the `time` crate. | [time](https://crates.io/crates/time) 0.2 | no | +//! | `with-time-0_2` | Enable support for the 0.2 version of the `time` crate. | [time](https://crates.io/crates/time/0.2.0) 0.2 | no | +//! | `with-time-0_3` | Enable support for the 0.3 version of the `time` crate. | [time](https://crates.io/crates/time/0.3.0) 0.3 | no | #![doc(html_root_url = "https://docs.rs/tokio-postgres/0.7")] #![warn(rust_2018_idioms, clippy::all, missing_docs)] diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index 54a111b3a..604e2de32 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -29,6 +29,8 @@ mod geo_types_07; mod serde_json_1; #[cfg(feature = "with-time-0_2")] mod time_02; +#[cfg(feature = "with-time-0_3")] +mod time_03; #[cfg(feature = "with-uuid-0_8")] mod uuid_08; diff --git a/tokio-postgres/tests/test/types/time_03.rs b/tokio-postgres/tests/test/types/time_03.rs new file mode 100644 index 000000000..df013c9bf --- /dev/null +++ b/tokio-postgres/tests/test/types/time_03.rs @@ -0,0 +1,149 @@ +use time_03::{format_description, OffsetDateTime, PrimitiveDateTime}; +use tokio_postgres::types::{Date, Timestamp}; + +use crate::types::test_type; + +// time 0.2 does not [yet?] support parsing fractional seconds +// https://github.com/time-rs/time/issues/226 + +#[tokio::test] +async fn test_primitive_date_time_params() { + fn make_check(time: &str) -> (Option, &str) { + let format = + format_description::parse("'[year]-[month]-[day] [hour]:[minute]:[second]'").unwrap(); + (Some(PrimitiveDateTime::parse(time, &format).unwrap()), time) + } + test_type( + "TIMESTAMP", + &[ + make_check("'1970-01-01 00:00:00'"), // .010000000 + make_check("'1965-09-25 11:19:33'"), // .100314000 + make_check("'2010-02-09 23:11:45'"), // .120200000 + (None, "NULL"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_with_special_primitive_date_time_params() { + fn make_check(time: &str) -> (Timestamp, &str) { + let format = + format_description::parse("'[year]-[month]-[day] [hour]:[minute]:[second]'").unwrap(); + ( + Timestamp::Value(PrimitiveDateTime::parse(time, &format).unwrap()), + time, + ) + } + test_type( + "TIMESTAMP", + &[ + make_check("'1970-01-01 00:00:00'"), // .010000000 + make_check("'1965-09-25 11:19:33'"), // .100314000 + make_check("'2010-02-09 23:11:45'"), // .120200000 + (Timestamp::PosInfinity, "'infinity'"), + (Timestamp::NegInfinity, "'-infinity'"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_offset_date_time_params() { + fn make_check(time: &str) -> (Option, &str) { + let format = + format_description::parse("'[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour sign:mandatory][offset_minute]'").unwrap(); + (Some(OffsetDateTime::parse(time, &format).unwrap()), time) + } + test_type( + "TIMESTAMP WITH TIME ZONE", + &[ + make_check("'1970-01-01 00:00:00 +0000'"), // .010000000 + make_check("'1965-09-25 11:19:33 +0000'"), // .100314000 + make_check("'2010-02-09 23:11:45 +0000'"), // .120200000 + (None, "NULL"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_with_special_offset_date_time_params() { + fn make_check(time: &str) -> (Timestamp, &str) { + let format = + format_description::parse("'[year]-[month]-[day] [hour]:[minute]:[second] [offset_hour sign:mandatory][offset_minute]'").unwrap(); + ( + Timestamp::Value(OffsetDateTime::parse(time, &format).unwrap()), + time, + ) + } + test_type( + "TIMESTAMP WITH TIME ZONE", + &[ + make_check("'1970-01-01 00:00:00 +0000'"), // .010000000 + make_check("'1965-09-25 11:19:33 +0000'"), // .100314000 + make_check("'2010-02-09 23:11:45 +0000'"), // .120200000 + (Timestamp::PosInfinity, "'infinity'"), + (Timestamp::NegInfinity, "'-infinity'"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_date_params() { + fn make_check(date: &str) -> (Option, &str) { + let format = format_description::parse("'[year]-[month]-[day]'").unwrap(); + (Some(time_03::Date::parse(date, &format).unwrap()), date) + } + test_type( + "DATE", + &[ + make_check("'1970-01-01'"), + make_check("'1965-09-25'"), + make_check("'2010-02-09'"), + (None, "NULL"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_with_special_date_params() { + fn make_check(date: &str) -> (Date, &str) { + let format = format_description::parse("'[year]-[month]-[day]'").unwrap(); + ( + Date::Value(time_03::Date::parse(date, &format).unwrap()), + date, + ) + } + test_type( + "DATE", + &[ + make_check("'1970-01-01'"), + make_check("'1965-09-25'"), + make_check("'2010-02-09'"), + (Date::PosInfinity, "'infinity'"), + (Date::NegInfinity, "'-infinity'"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_time_params() { + fn make_check(time: &str) -> (Option, &str) { + let format = format_description::parse("'[hour]:[minute]:[second]'").unwrap(); + (Some(time_03::Time::parse(time, &format).unwrap()), time) + } + test_type( + "TIME", + &[ + make_check("'00:00:00'"), // .010000000 + make_check("'11:19:33'"), // .100314000 + make_check("'23:11:45'"), // .120200000 + (None, "NULL"), + ], + ) + .await; +} From 34d8b77644880dbaef1bcd7e8aa246dc59e90d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Fri, 24 Sep 2021 08:41:18 +0300 Subject: [PATCH 130/420] Add feature gates for doctests --- postgres-native-tls/src/lib.rs | 6 ++++++ postgres-openssl/src/lib.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/postgres-native-tls/src/lib.rs b/postgres-native-tls/src/lib.rs index 2f2e6e6ad..a06f185b5 100644 --- a/postgres-native-tls/src/lib.rs +++ b/postgres-native-tls/src/lib.rs @@ -4,10 +4,12 @@ //! //! ```no_run //! use native_tls::{Certificate, TlsConnector}; +//! # #[cfg(feature = "runtime")] //! use postgres_native_tls::MakeTlsConnector; //! use std::fs; //! //! # fn main() -> Result<(), Box> { +//! # #[cfg(feature = "runtime")] { //! let cert = fs::read("database_cert.pem")?; //! let cert = Certificate::from_pem(&cert)?; //! let connector = TlsConnector::builder() @@ -19,6 +21,7 @@ //! "host=localhost user=postgres sslmode=require", //! connector, //! ); +//! # } //! //! // ... //! # Ok(()) @@ -27,10 +30,12 @@ //! //! ```no_run //! use native_tls::{Certificate, TlsConnector}; +//! # #[cfg(feature = "runtime")] //! use postgres_native_tls::MakeTlsConnector; //! use std::fs; //! //! # fn main() -> Result<(), Box> { +//! # #[cfg(feature = "runtime")] { //! let cert = fs::read("database_cert.pem")?; //! let cert = Certificate::from_pem(&cert)?; //! let connector = TlsConnector::builder() @@ -42,6 +47,7 @@ //! "host=localhost user=postgres sslmode=require", //! connector, //! )?; +//! # } //! # Ok(()) //! # } //! ``` diff --git a/postgres-openssl/src/lib.rs b/postgres-openssl/src/lib.rs index f3c0b9309..49fc2807c 100644 --- a/postgres-openssl/src/lib.rs +++ b/postgres-openssl/src/lib.rs @@ -4,9 +4,11 @@ //! //! ```no_run //! use openssl::ssl::{SslConnector, SslMethod}; +//! # #[cfg(feature = "runtime")] //! use postgres_openssl::MakeTlsConnector; //! //! # fn main() -> Result<(), Box> { +//! # #[cfg(feature = "runtime")] { //! let mut builder = SslConnector::builder(SslMethod::tls())?; //! builder.set_ca_file("database_cert.pem")?; //! let connector = MakeTlsConnector::new(builder.build()); @@ -15,6 +17,7 @@ //! "host=localhost user=postgres sslmode=require", //! connector, //! ); +//! # } //! //! // ... //! # Ok(()) @@ -23,9 +26,11 @@ //! //! ```no_run //! use openssl::ssl::{SslConnector, SslMethod}; +//! # #[cfg(feature = "runtime")] //! use postgres_openssl::MakeTlsConnector; //! //! # fn main() -> Result<(), Box> { +//! # #[cfg(feature = "runtime")] { //! let mut builder = SslConnector::builder(SslMethod::tls())?; //! builder.set_ca_file("database_cert.pem")?; //! let connector = MakeTlsConnector::new(builder.build()); @@ -34,6 +39,7 @@ //! "host=localhost user=postgres sslmode=require", //! connector, //! )?; +//! # } //! //! // ... //! # Ok(()) From c7785d0b10bf629b1dbf915d24f370d5e11da4f4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 29 Sep 2021 19:24:46 -0400 Subject: [PATCH 131/420] Release postgres-types v0.2.2 --- postgres-types/CHANGELOG.md | 8 ++++++++ postgres-types/Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index 83bc4d1fd..f8b2835eb 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## v0.2.2 - 2021-09-29 + +### Added + +* Added support for `eui48` 1.0 via the `with-eui48-1` feature. +* Added `ToSql` and `FromSql` implementations for array types via the `array-impls` feature. +* Added support for `time` 0.3 via the `with-time-0_3` feature. + ## v0.2.1 - 2021-04-03 ### Added diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 8fc6ed107..7eca3fbcf 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-types" -version = "0.2.1" +version = "0.2.2" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From 349c38b1fe77eae6b27a2ca65d760bff984382e7 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 29 Sep 2021 19:27:15 -0400 Subject: [PATCH 132/420] Release postgres-protocol v0.6.2 --- postgres-protocol/CHANGELOG.md | 6 ++++++ postgres-protocol/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres-protocol/CHANGELOG.md b/postgres-protocol/CHANGELOG.md index 7a51cb192..eb37f5883 100644 --- a/postgres-protocol/CHANGELOG.md +++ b/postgres-protocol/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.6.2 - 2021-09-29 + +### Changed + +* Upgraded `hmac`. + ## v0.6.1 - 2021-04-03 ### Added diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index d4ae8c301..a4ed3e907 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-protocol" -version = "0.6.1" +version = "0.6.2" authors = ["Steven Fackler "] edition = "2018" description = "Low level Postgres protocol APIs" From 8542d078bfcd88dcb92ceae7ec9d17364586f3a2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 29 Sep 2021 19:34:32 -0400 Subject: [PATCH 133/420] Release tokio-postgres v0.7.2 --- tokio-postgres/CHANGELOG.md | 13 +++++++++++++ tokio-postgres/Cargo.toml | 4 ++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 3a7aa2ae7..2c2ea5bc8 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## v0.7.2 - 2021-09-29 + +### Fixed + +* Fixed a deadlock when pipelined requests concurrently prepare cached typeinfo queries. + +### Added + +* Added `SimpleQueryRow::columns`. +* Added support for `eui48` 1.0 via the `with-eui48-1` feature. +* Added `FromSql` and `ToSql` implementations for arrays via the `array-impls` feature. +* Added support for `time` 0.3 via the `with-time-0_3` feature. + ## v0.7.2 - 2021-04-25 ### Fixed diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index d35a323a1..65f65d641 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.7.2" +version = "0.7.3" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -51,7 +51,7 @@ percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.10" postgres-protocol = { version = "0.6.1", path = "../postgres-protocol" } -postgres-types = { version = "0.2.1", path = "../postgres-types" } +postgres-types = { version = "0.2.2", path = "../postgres-types" } socket2 = "0.4" tokio = { version = "1.0", features = ["io-util"] } tokio-util = { version = "0.6", features = ["codec"] } From d45461614aca87022c17a2cc26b22325bf161fa5 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 29 Sep 2021 19:38:29 -0400 Subject: [PATCH 134/420] Release postgres v0.19.2 --- postgres/CHANGELOG.md | 9 +++++++++ postgres/Cargo.toml | 4 ++-- tokio-postgres/CHANGELOG.md | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index e68dedc5b..6af8d914b 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,5 +1,14 @@ # Change Log +## v0.19.2 - 2021-09-29 + +### Added + +* Added `SimpleQueryRow::columns`. +* Added support for `eui48` 1.0 via the `with-eui48-1` feature. +* Added `FromSql` and `ToSql` implementations for arrays via the `array-impls` feature. +* Added support for `time` 0.3 via the `with-time-0_3` feature. + ## v0.19.1 - 2021-04-03 ### Added diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 3d1c20234..b61e42aca 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.19.1" +version = "0.19.2" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -37,7 +37,7 @@ with-time-0_3 = ["tokio-postgres/with-time-0_3"] bytes = "1.0" fallible-iterator = "0.2" futures = "0.3" -tokio-postgres = { version = "0.7.1", path = "../tokio-postgres" } +tokio-postgres = { version = "0.7.2", path = "../tokio-postgres" } tokio = { version = "1.0", features = ["rt", "time"] } log = "0.4" diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 2c2ea5bc8..9e70c0045 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,6 +1,6 @@ # Change Log -## v0.7.2 - 2021-09-29 +## v0.7.3 - 2021-09-29 ### Fixed From b2df11579f8b49728d3096b6bd6da0b7ab27ccf0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 19 Oct 2021 19:36:14 -0400 Subject: [PATCH 135/420] Fix commit-time error reporting Closes #832 --- tokio-postgres/src/query.rs | 25 ++++++++++++++----------- tokio-postgres/tests/test/main.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index f139ed915..cdb952190 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -99,11 +99,12 @@ where }; let mut responses = start(client, buf).await?; + let mut rows = 0; loop { match responses.next().await? { Message::DataRow(_) => {} Message::CommandComplete(body) => { - let rows = body + rows = body .tag() .map_err(Error::parse)? .rsplit(' ') @@ -111,9 +112,9 @@ where .unwrap() .parse() .unwrap_or(0); - return Ok(rows); } - Message::EmptyQueryResponse => return Ok(0), + Message::EmptyQueryResponse => rows = 0, + Message::ReadyForQuery(_) => return Ok(rows), _ => return Err(Error::unexpected_message()), } } @@ -203,15 +204,17 @@ impl Stream for RowStream { fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let this = self.project(); - match ready!(this.responses.poll_next(cx)?) { - Message::DataRow(body) => { - Poll::Ready(Some(Ok(Row::new(this.statement.clone(), body)?))) + loop { + match ready!(this.responses.poll_next(cx)?) { + Message::DataRow(body) => { + return Poll::Ready(Some(Ok(Row::new(this.statement.clone(), body)?))) + } + Message::EmptyQueryResponse + | Message::CommandComplete(_) + | Message::PortalSuspended => {} + Message::ReadyForQuery(_) => return Poll::Ready(None), + _ => return Poll::Ready(Some(Err(Error::unexpected_message()))), } - Message::EmptyQueryResponse - | Message::CommandComplete(_) - | Message::PortalSuspended => Poll::Ready(None), - Message::ErrorResponse(body) => Poll::Ready(Some(Err(Error::db(body)))), - _ => Poll::Ready(Some(Err(Error::unexpected_message()))), } } } diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index c0b4bf202..31d7fa295 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -805,3 +805,29 @@ async fn query_opt() { .err() .unwrap(); } + +#[tokio::test] +async fn deferred_constraint() { + let client = connect("user=postgres").await; + + client + .batch_execute( + " + CREATE TEMPORARY TABLE t ( + i INT, + UNIQUE (i) DEFERRABLE INITIALLY DEFERRED + ); + ", + ) + .await + .unwrap(); + + client + .execute("INSERT INTO t (i) VALUES (1)", &[]) + .await + .unwrap(); + client + .execute("INSERT INTO t (i) VALUES (1)", &[]) + .await + .unwrap_err(); +} From 0adcf58555fa1a5f42bdab512ea462ca993cad62 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 19 Oct 2021 19:58:49 -0400 Subject: [PATCH 136/420] Release tokio-postgres v0.7.4 --- tokio-postgres/CHANGELOG.md | 6 ++++++ tokio-postgres/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 9e70c0045..34b4fc1d9 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.7.4 - 2021-10-19 + +### Fixed + +* Fixed reporting of commit-time errors triggered by deferred constraints. + ## v0.7.3 - 2021-09-29 ### Fixed diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 65f65d641..17286dc21 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.7.3" +version = "0.7.4" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From f6189a95f24af45068ecfd6e3c4e6b71ac8e43fe Mon Sep 17 00:00:00 2001 From: ilslv Date: Thu, 28 Oct 2021 12:10:30 +0300 Subject: [PATCH 137/420] Fix transaction not being rolled back on `Client::transaction()` `Future` dropped before completion --- tokio-postgres/src/client.rs | 41 +++++++++- tokio-postgres/tests/test/main.rs | 122 +++++++++++++++++++++++++++++- 2 files changed, 159 insertions(+), 4 deletions(-) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 4a099d941..dea77da94 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -1,4 +1,4 @@ -use crate::codec::BackendMessages; +use crate::codec::{BackendMessages, FrontendMessage}; use crate::config::{Host, SslMode}; use crate::connection::{Request, RequestMessages}; use crate::copy_out::CopyOutStream; @@ -19,7 +19,7 @@ use fallible_iterator::FallibleIterator; use futures::channel::mpsc; use futures::{future, pin_mut, ready, StreamExt, TryStreamExt}; use parking_lot::Mutex; -use postgres_protocol::message::backend::Message; +use postgres_protocol::message::{backend::Message, frontend}; use postgres_types::BorrowToSql; use std::collections::HashMap; use std::fmt; @@ -488,7 +488,42 @@ impl Client { /// /// The transaction will roll back by default - use the `commit` method to commit it. pub async fn transaction(&mut self) -> Result, Error> { - self.batch_execute("BEGIN").await?; + struct RollbackIfNotDone<'me> { + client: &'me Client, + done: bool, + } + + impl<'a> Drop for RollbackIfNotDone<'a> { + fn drop(&mut self) { + if self.done { + return; + } + + let buf = self.client.inner().with_buf(|buf| { + frontend::query("ROLLBACK", buf).unwrap(); + buf.split().freeze() + }); + let _ = self + .client + .inner() + .send(RequestMessages::Single(FrontendMessage::Raw(buf))); + } + } + + // This is done, as `Future` created by this method can be dropped after + // `RequestMessages` is synchronously send to the `Connection` by + // `batch_execute()`, but before `Responses` is asynchronously polled to + // completion. In that case `Transaction` won't be created and thus + // won't be rolled back. + { + let mut cleaner = RollbackIfNotDone { + client: self, + done: false, + }; + self.batch_execute("BEGIN").await?; + cleaner.done = true; + } + Ok(Transaction::new(self)) } diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index 31d7fa295..dcfbc5308 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -3,9 +3,12 @@ use bytes::{Bytes, BytesMut}; use futures::channel::mpsc; use futures::{ - future, join, pin_mut, stream, try_join, FutureExt, SinkExt, StreamExt, TryStreamExt, + future, join, pin_mut, stream, try_join, Future, FutureExt, SinkExt, StreamExt, TryStreamExt, }; +use pin_project_lite::pin_project; use std::fmt::Write; +use std::pin::Pin; +use std::task::{Context, Poll}; use std::time::Duration; use tokio::net::TcpStream; use tokio::time; @@ -22,6 +25,35 @@ mod parse; mod runtime; mod types; +pin_project! { + /// Polls `F` at most `polls_left` times returning `Some(F::Output)` if + /// [`Future`] returned [`Poll::Ready`] or [`None`] otherwise. + struct Cancellable { + #[pin] + fut: F, + polls_left: usize, + } +} + +impl Future for Cancellable { + type Output = Option; + + fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { + let this = self.project(); + match this.fut.poll(ctx) { + Poll::Ready(r) => Poll::Ready(Some(r)), + Poll::Pending => { + *this.polls_left = this.polls_left.saturating_sub(1); + if *this.polls_left == 0 { + Poll::Ready(None) + } else { + Poll::Pending + } + } + } + } +} + async fn connect_raw(s: &str) -> Result<(Client, Connection), Error> { let socket = TcpStream::connect("127.0.0.1:5433").await.unwrap(); let config = s.parse::().unwrap(); @@ -35,6 +67,20 @@ async fn connect(s: &str) -> Client { client } +async fn current_transaction_id(client: &Client) -> i64 { + client + .query("SELECT txid_current()", &[]) + .await + .unwrap() + .pop() + .unwrap() + .get::<_, i64>("txid_current") +} + +async fn in_transaction(client: &Client) -> bool { + current_transaction_id(client).await == current_transaction_id(client).await +} + #[tokio::test] async fn plain_password_missing() { connect_raw("user=pass_user dbname=postgres") @@ -377,6 +423,80 @@ async fn transaction_rollback() { assert_eq!(rows.len(), 0); } +#[tokio::test] +async fn transaction_future_cancellation() { + let mut client = connect("user=postgres").await; + + for i in 0.. { + let done = { + let txn = client.transaction(); + let fut = Cancellable { + fut: txn, + polls_left: i, + }; + fut.await + .map(|res| res.expect("transaction failed")) + .is_some() + }; + + assert!(!in_transaction(&client).await); + + if done { + break; + } + } +} + +#[tokio::test] +async fn transaction_commit_future_cancellation() { + let mut client = connect("user=postgres").await; + + for i in 0.. { + let done = { + let txn = client.transaction().await.unwrap(); + let commit = txn.commit(); + let fut = Cancellable { + fut: commit, + polls_left: i, + }; + fut.await + .map(|res| res.expect("transaction failed")) + .is_some() + }; + + assert!(!in_transaction(&client).await); + + if done { + break; + } + } +} + +#[tokio::test] +async fn transaction_rollback_future_cancellation() { + let mut client = connect("user=postgres").await; + + for i in 0.. { + let done = { + let txn = client.transaction().await.unwrap(); + let rollback = txn.rollback(); + let fut = Cancellable { + fut: rollback, + polls_left: i, + }; + fut.await + .map(|res| res.expect("transaction failed")) + .is_some() + }; + + assert!(!in_transaction(&client).await); + + if done { + break; + } + } +} + #[tokio::test] async fn transaction_rollback_drop() { let mut client = connect("user=postgres").await; From 24b01add826f0844df1eb75f64cac42eda88bcd6 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 28 Oct 2021 19:08:38 -0400 Subject: [PATCH 138/420] Don't use a built container for test postgres --- .github/workflows/ci.yml | 6 +----- docker-compose.yml | 8 ++++++-- docker/Dockerfile | 3 --- 3 files changed, 7 insertions(+), 10 deletions(-) delete mode 100644 docker/Dockerfile diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b3a3420d..e38dea88d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,13 +50,9 @@ jobs: test: name: test runs-on: ubuntu-latest - services: - postgres: - image: sfackler/rust-postgres-test:6 - ports: - - 5433:5433 steps: - uses: actions/checkout@v2 + - run: docker compose up -d - uses: sfackler/actions/rustup@master with: version: 1.51.0 diff --git a/docker-compose.yml b/docker-compose.yml index d44fbe866..0ed44148d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,10 @@ version: '2' services: postgres: - image: "sfackler/rust-postgres-test:6" + image: postgres:14 ports: - - 5433:5433 + - 5433:5433 + volumes: + - ./docker/sql_setup.sh:/docker-entrypoint-initdb.d/sql_setup.sh + environment: + POSTGRES_PASSWORD: postgres diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index 1dd7f3db6..000000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM postgres:12 - -COPY sql_setup.sh /docker-entrypoint-initdb.d/ From a47a8edf98763846003b51f88fc116704bd7c64a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 28 Oct 2021 19:16:57 -0400 Subject: [PATCH 139/420] Remove src/url.rs from THIRD_PARTY It hasn't existed in the project for quite a while --- THIRD_PARTY | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/THIRD_PARTY b/THIRD_PARTY index 80336ea0f..05e5ac435 100644 --- a/THIRD_PARTY +++ b/THIRD_PARTY @@ -27,33 +27,3 @@ BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - -------------------------------------------------------------------------------- - -* src/url.rs has been copied from Rust - -Copyright (c) 2014 The Rust Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. From 33703689e0addf1af4ac34762391020630c2b7be Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 28 Oct 2021 19:22:13 -0400 Subject: [PATCH 140/420] Clean up licenses --- LICENSE | 20 --- LICENSE-APACHE | 201 ++++++++++++++++++++++++++++ LICENSE-MIT | 22 ++++ postgres-derive/LICENSE-APACHE | 202 +---------------------------- postgres-derive/LICENSE-MIT | 23 +--- postgres-native-tls/LICENSE-APACHE | 2 +- postgres-native-tls/LICENSE-MIT | 2 +- postgres-openssl/LICENSE-APACHE | 2 +- postgres-openssl/LICENSE-MIT | 2 +- postgres-protocol/LICENSE-APACHE | 202 +---------------------------- postgres-protocol/LICENSE-MIT | 23 +--- postgres-types/LICENSE-APACHE | 202 +---------------------------- postgres-types/LICENSE-MIT | 23 +--- postgres/LICENSE-APACHE | 202 +---------------------------- postgres/LICENSE-MIT | 23 +--- tokio-postgres/LICENSE-APACHE | 202 +---------------------------- tokio-postgres/LICENSE-MIT | 23 +--- 17 files changed, 237 insertions(+), 1139 deletions(-) delete mode 100644 LICENSE create mode 100644 LICENSE-APACHE create mode 100644 LICENSE-MIT mode change 100644 => 120000 postgres-derive/LICENSE-APACHE mode change 100644 => 120000 postgres-derive/LICENSE-MIT mode change 100644 => 120000 postgres-protocol/LICENSE-APACHE mode change 100644 => 120000 postgres-protocol/LICENSE-MIT mode change 100644 => 120000 postgres-types/LICENSE-APACHE mode change 100644 => 120000 postgres-types/LICENSE-MIT mode change 100644 => 120000 postgres/LICENSE-APACHE mode change 100644 => 120000 postgres/LICENSE-MIT mode change 100644 => 120000 tokio-postgres/LICENSE-APACHE mode change 100644 => 120000 tokio-postgres/LICENSE-MIT diff --git a/LICENSE b/LICENSE deleted file mode 100644 index c7e577c00..000000000 --- a/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013-2017 Steven Fackler - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 000000000..71803aea1 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016 Steven Fackler + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/postgres-derive/LICENSE-APACHE b/postgres-derive/LICENSE-APACHE deleted file mode 100644 index 16fe87b06..000000000 --- a/postgres-derive/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/postgres-derive/LICENSE-APACHE b/postgres-derive/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/postgres-derive/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/postgres-derive/LICENSE-MIT b/postgres-derive/LICENSE-MIT deleted file mode 100644 index 71803aea1..000000000 --- a/postgres-derive/LICENSE-MIT +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Steven Fackler - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/postgres-derive/LICENSE-MIT b/postgres-derive/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/postgres-derive/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/postgres-native-tls/LICENSE-APACHE b/postgres-native-tls/LICENSE-APACHE index b9e46b0fc..965b606f3 120000 --- a/postgres-native-tls/LICENSE-APACHE +++ b/postgres-native-tls/LICENSE-APACHE @@ -1 +1 @@ -../tokio-postgres/LICENSE-APACHE \ No newline at end of file +../LICENSE-APACHE \ No newline at end of file diff --git a/postgres-native-tls/LICENSE-MIT b/postgres-native-tls/LICENSE-MIT index 162832a42..76219eb72 120000 --- a/postgres-native-tls/LICENSE-MIT +++ b/postgres-native-tls/LICENSE-MIT @@ -1 +1 @@ -../tokio-postgres/LICENSE-MIT \ No newline at end of file +../LICENSE-MIT \ No newline at end of file diff --git a/postgres-openssl/LICENSE-APACHE b/postgres-openssl/LICENSE-APACHE index b9e46b0fc..965b606f3 120000 --- a/postgres-openssl/LICENSE-APACHE +++ b/postgres-openssl/LICENSE-APACHE @@ -1 +1 @@ -../tokio-postgres/LICENSE-APACHE \ No newline at end of file +../LICENSE-APACHE \ No newline at end of file diff --git a/postgres-openssl/LICENSE-MIT b/postgres-openssl/LICENSE-MIT index 162832a42..76219eb72 120000 --- a/postgres-openssl/LICENSE-MIT +++ b/postgres-openssl/LICENSE-MIT @@ -1 +1 @@ -../tokio-postgres/LICENSE-MIT \ No newline at end of file +../LICENSE-MIT \ No newline at end of file diff --git a/postgres-protocol/LICENSE-APACHE b/postgres-protocol/LICENSE-APACHE deleted file mode 100644 index 16fe87b06..000000000 --- a/postgres-protocol/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/postgres-protocol/LICENSE-APACHE b/postgres-protocol/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/postgres-protocol/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/postgres-protocol/LICENSE-MIT b/postgres-protocol/LICENSE-MIT deleted file mode 100644 index 71803aea1..000000000 --- a/postgres-protocol/LICENSE-MIT +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Steven Fackler - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/postgres-protocol/LICENSE-MIT b/postgres-protocol/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/postgres-protocol/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/postgres-types/LICENSE-APACHE b/postgres-types/LICENSE-APACHE deleted file mode 100644 index 16fe87b06..000000000 --- a/postgres-types/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/postgres-types/LICENSE-APACHE b/postgres-types/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/postgres-types/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/postgres-types/LICENSE-MIT b/postgres-types/LICENSE-MIT deleted file mode 100644 index 71803aea1..000000000 --- a/postgres-types/LICENSE-MIT +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Steven Fackler - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/postgres-types/LICENSE-MIT b/postgres-types/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/postgres-types/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/postgres/LICENSE-APACHE b/postgres/LICENSE-APACHE deleted file mode 100644 index 16fe87b06..000000000 --- a/postgres/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/postgres/LICENSE-APACHE b/postgres/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/postgres/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/postgres/LICENSE-MIT b/postgres/LICENSE-MIT deleted file mode 100644 index 71803aea1..000000000 --- a/postgres/LICENSE-MIT +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Steven Fackler - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/postgres/LICENSE-MIT b/postgres/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/postgres/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file diff --git a/tokio-postgres/LICENSE-APACHE b/tokio-postgres/LICENSE-APACHE deleted file mode 100644 index 16fe87b06..000000000 --- a/tokio-postgres/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/tokio-postgres/LICENSE-APACHE b/tokio-postgres/LICENSE-APACHE new file mode 120000 index 000000000..965b606f3 --- /dev/null +++ b/tokio-postgres/LICENSE-APACHE @@ -0,0 +1 @@ +../LICENSE-APACHE \ No newline at end of file diff --git a/tokio-postgres/LICENSE-MIT b/tokio-postgres/LICENSE-MIT deleted file mode 100644 index 71803aea1..000000000 --- a/tokio-postgres/LICENSE-MIT +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Steven Fackler - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/tokio-postgres/LICENSE-MIT b/tokio-postgres/LICENSE-MIT new file mode 120000 index 000000000..76219eb72 --- /dev/null +++ b/tokio-postgres/LICENSE-MIT @@ -0,0 +1 @@ +../LICENSE-MIT \ No newline at end of file From 8bb5712406c7c3c9763daa553de525cad55785d4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 28 Oct 2021 19:32:33 -0400 Subject: [PATCH 141/420] Implement ToStatement for String Closes #794 --- tokio-postgres/src/to_statement.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tokio-postgres/src/to_statement.rs b/tokio-postgres/src/to_statement.rs index 3ff82493c..427f77dd7 100644 --- a/tokio-postgres/src/to_statement.rs +++ b/tokio-postgres/src/to_statement.rs @@ -47,3 +47,11 @@ impl ToStatement for str { } impl Sealed for str {} + +impl ToStatement for String { + fn __convert(&self) -> ToStatementType<'_> { + ToStatementType::Query(self) + } +} + +impl Sealed for String {} From 84fa5fa1d007e95e18bef95f01e9a065ccf1e415 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 29 Oct 2021 21:33:07 -0400 Subject: [PATCH 142/420] Release tokio-postgres v0.7.5 --- tokio-postgres/CHANGELOG.md | 6 ++++++ tokio-postgres/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 34b4fc1d9..eca196f06 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.7.5 - 2021-10-29 + +### Fixed + +* Fixed a bug where the client could enter into a transaction if the `Client::transaction` future was dropped before completion. + ## v0.7.4 - 2021-10-19 ### Fixed diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 17286dc21..5974fe64f 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.7.4" +version = "0.7.5" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From 6c407d39d5037d01c14f9c830a6f798dd94d2e82 Mon Sep 17 00:00:00 2001 From: Ruslan Talpa Date: Mon, 1 Nov 2021 12:31:59 +0200 Subject: [PATCH 143/420] implement Unknown encoding for query parameters --- postgres-types/src/lib.rs | 42 +++++++++++++++++++++++++++++++++++-- tokio-postgres/src/query.rs | 4 +++- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 2a953db2f..0c93bed2e 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -769,6 +769,40 @@ pub trait ToSql: fmt::Debug { ty: &Type, out: &mut BytesMut, ) -> Result>; + + /// Specify the encode format + fn encode_format(&self) -> i16 { 1 } + + /// return string representation + fn as_string(&self) -> String { + panic!("as_string not implemented for {:?}", self) + } +} + + +/// A Wrapper type used for sending query parameters encoded as unknown. +#[derive(Debug)] +pub struct Unknown<'a>(pub &'a (dyn ToSql + Sync)); + +impl ToSql for Unknown<'_> { + fn to_sql( + &self, + _ty: &Type, + out: &mut BytesMut, + ) -> Result> { + match *self { + Unknown(val) => { + types::text_to_sql(&val.as_string(), out); + Ok(IsNull::No) + } + } + } + + fn accepts(_ty: &Type) -> bool { true } + + fn encode_format(&self) -> i16 { 0 } + + to_sql_checked!(); } impl<'a, T> ToSql for &'a T @@ -905,7 +939,7 @@ impl<'a> ToSql for &'a str { _ => false, } } - + fn as_string(&self) -> String { self.to_string() } to_sql_checked!(); } @@ -929,7 +963,7 @@ impl ToSql for String { fn accepts(ty: &Type) -> bool { <&str as ToSql>::accepts(ty) } - + fn as_string(&self) -> String { self.clone() } to_sql_checked!(); } @@ -944,6 +978,10 @@ macro_rules! simple_to { Ok(IsNull::No) } + fn as_string(&self) -> String { + format!("{}", &self) + } + accepts!($($expected),+); to_sql_checked!(); diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index cdb952190..6de9c5b88 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -156,6 +156,8 @@ where I: IntoIterator, I::IntoIter: ExactSizeIterator, { + + let (param_formats, params):(Vec<_>, Vec<_>) = params.into_iter().map(|p| (p.borrow_to_sql().encode_format(),p)).unzip(); let params = params.into_iter(); assert!( @@ -169,7 +171,7 @@ where let r = frontend::bind( portal, statement.name(), - Some(1), + param_formats, params.zip(statement.params()).enumerate(), |(idx, (param, ty)), buf| match param.borrow_to_sql().to_sql_checked(ty, buf) { Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No), From 08b7c65f8d367a701054327918ca653d8a21d66e Mon Sep 17 00:00:00 2001 From: Ruslan Talpa Date: Tue, 2 Nov 2021 11:13:25 +0200 Subject: [PATCH 144/420] remove as_string --- postgres-types/src/lib.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 0c93bed2e..02fb48ed1 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -772,17 +772,12 @@ pub trait ToSql: fmt::Debug { /// Specify the encode format fn encode_format(&self) -> i16 { 1 } - - /// return string representation - fn as_string(&self) -> String { - panic!("as_string not implemented for {:?}", self) - } } /// A Wrapper type used for sending query parameters encoded as unknown. #[derive(Debug)] -pub struct Unknown<'a>(pub &'a (dyn ToSql + Sync)); +pub struct Unknown<'a>(pub &'a str); impl ToSql for Unknown<'_> { fn to_sql( @@ -792,7 +787,7 @@ impl ToSql for Unknown<'_> { ) -> Result> { match *self { Unknown(val) => { - types::text_to_sql(&val.as_string(), out); + types::text_to_sql(val, out); Ok(IsNull::No) } } @@ -939,7 +934,7 @@ impl<'a> ToSql for &'a str { _ => false, } } - fn as_string(&self) -> String { self.to_string() } + to_sql_checked!(); } @@ -963,7 +958,7 @@ impl ToSql for String { fn accepts(ty: &Type) -> bool { <&str as ToSql>::accepts(ty) } - fn as_string(&self) -> String { self.clone() } + to_sql_checked!(); } @@ -978,10 +973,6 @@ macro_rules! simple_to { Ok(IsNull::No) } - fn as_string(&self) -> String { - format!("{}", &self) - } - accepts!($($expected),+); to_sql_checked!(); From 683868850eda0f02a0c8f2776eb20d627c8581e3 Mon Sep 17 00:00:00 2001 From: Ruslan Talpa Date: Fri, 19 Nov 2021 09:22:36 +0200 Subject: [PATCH 145/420] remove "Unknown" and add Format enum --- postgres-types/src/lib.rs | 39 ++++++++++++++++--------------------- tokio-postgres/src/query.rs | 3 +-- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 02fb48ed1..0121cbb6e 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -771,35 +771,30 @@ pub trait ToSql: fmt::Debug { ) -> Result>; /// Specify the encode format - fn encode_format(&self) -> i16 { 1 } + fn encode_format(&self) -> Format { Format::Binary } } +/// Supported Postgres message format types +/// +/// Using Text format in a message assumes a Postgres `SERVER_ENCODING` of `UTF8` +pub enum Format { + /// Text format (UTF-8) + Text, + /// Compact, typed binary format + Binary, +} -/// A Wrapper type used for sending query parameters encoded as unknown. -#[derive(Debug)] -pub struct Unknown<'a>(pub &'a str); - -impl ToSql for Unknown<'_> { - fn to_sql( - &self, - _ty: &Type, - out: &mut BytesMut, - ) -> Result> { - match *self { - Unknown(val) => { - types::text_to_sql(val, out); - Ok(IsNull::No) - } +/// Convert from `Format` to the Postgres integer representation of those formats +impl From for i16 { + fn from(format: Format) -> Self { + match format { + Format::Text => 0, + Format::Binary => 1, } } - - fn accepts(_ty: &Type) -> bool { true } - - fn encode_format(&self) -> i16 { 0 } - - to_sql_checked!(); } + impl<'a, T> ToSql for &'a T where T: ToSql, diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index 6de9c5b88..af57e2aec 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -156,8 +156,7 @@ where I: IntoIterator, I::IntoIter: ExactSizeIterator, { - - let (param_formats, params):(Vec<_>, Vec<_>) = params.into_iter().map(|p| (p.borrow_to_sql().encode_format(),p)).unzip(); + let (param_formats, params):(Vec<_>, Vec<_>) = params.into_iter().map(|p|->(i16, P){(p.borrow_to_sql().encode_format().into(),p)}).unzip(); let params = params.into_iter(); assert!( From dc591ff2ca5a51e4f7f3543e1321292b5a1dadea Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 23 Nov 2021 23:40:00 -0500 Subject: [PATCH 146/420] Fix handling of raw ident fields in derive --- postgres-derive-test/src/composites.rs | 23 +++++++++++++++++++++++ postgres-derive/src/composites.rs | 8 +++++++- postgres-derive/src/fromsql.rs | 6 +++--- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/postgres-derive-test/src/composites.rs b/postgres-derive-test/src/composites.rs index 5efd3944c..ed60bf48f 100644 --- a/postgres-derive-test/src/composites.rs +++ b/postgres-derive-test/src/composites.rs @@ -215,3 +215,26 @@ fn wrong_type() { .unwrap_err(); assert!(err.source().unwrap().is::()); } + +#[test] +fn raw_ident_field() { + #[derive(FromSql, ToSql, Debug, PartialEq)] + #[postgres(name = "inventory_item")] + struct InventoryItem { + r#type: String, + } + + let mut conn = Client::connect("user=postgres host=localhost port=5433", NoTls).unwrap(); + conn.batch_execute( + "CREATE TYPE pg_temp.inventory_item AS ( + type TEXT + )", + ) + .unwrap(); + + let item = InventoryItem { + r#type: "foo".to_owned(), + }; + + test_type(&mut conn, "inventory_item", &[(item, "ROW('foo')")]); +} diff --git a/postgres-derive/src/composites.rs b/postgres-derive/src/composites.rs index f5599d375..c1e495154 100644 --- a/postgres-derive/src/composites.rs +++ b/postgres-derive/src/composites.rs @@ -14,7 +14,13 @@ impl Field { let ident = raw.ident.as_ref().unwrap().clone(); Ok(Field { - name: overrides.name.unwrap_or_else(|| ident.to_string()), + name: overrides.name.unwrap_or_else(|| { + let name = ident.to_string(); + match name.strip_prefix("r#") { + Some(name) => name.to_string(), + None => name, + } + }), ident, type_: raw.ty.clone(), }) diff --git a/postgres-derive/src/fromsql.rs b/postgres-derive/src/fromsql.rs index e1ab6ffa7..3a59d6226 100644 --- a/postgres-derive/src/fromsql.rs +++ b/postgres-derive/src/fromsql.rs @@ -1,5 +1,5 @@ -use proc_macro2::{Span, TokenStream}; -use quote::quote; +use proc_macro2::TokenStream; +use quote::{format_ident, quote}; use std::iter; use syn::{Data, DataStruct, DeriveInput, Error, Fields, Ident}; @@ -119,7 +119,7 @@ fn domain_body(ident: &Ident, field: &syn::Field) -> TokenStream { fn composite_body(ident: &Ident, fields: &[Field]) -> TokenStream { let temp_vars = &fields .iter() - .map(|f| Ident::new(&format!("__{}", f.ident), Span::call_site())) + .map(|f| format_ident!("__{}", f.ident)) .collect::>(); let field_names = &fields.iter().map(|f| &f.name).collect::>(); let field_idents = &fields.iter().map(|f| &f.ident).collect::>(); From c5591c810ccba977bbf819b5d290d30e26300a3f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 23 Nov 2021 23:50:27 -0500 Subject: [PATCH 147/420] Release postgres-derive v0.4.1 --- postgres-derive/CHANGELOG.md | 6 ++++++ postgres-derive/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres-derive/CHANGELOG.md b/postgres-derive/CHANGELOG.md index 354f6f277..9bb3a752f 100644 --- a/postgres-derive/CHANGELOG.md +++ b/postgres-derive/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.4.1 - 2021-11-23 + +### Fixed + +* Fixed handling of struct fields using raw identifiers. + ## v0.4.0 - 2019-12-23 No changes diff --git a/postgres-derive/Cargo.toml b/postgres-derive/Cargo.toml index 293c294a0..1ce243a58 100644 --- a/postgres-derive/Cargo.toml +++ b/postgres-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-derive" -version = "0.4.0" +version = "0.4.1" authors = ["Steven Fackler "] license = "MIT/Apache-2.0" edition = "2018" From 8ead6e6c69e049c6b7ca67432e781a7429f76056 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 8 Dec 2021 18:30:44 -0500 Subject: [PATCH 148/420] Update hash crates --- postgres-protocol/Cargo.toml | 6 +++--- postgres-protocol/src/authentication/sasl.rs | 4 ++-- postgres-protocol/src/password/mod.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index a4ed3e907..638778f22 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -13,9 +13,9 @@ base64 = "0.13" byteorder = "1.0" bytes = "1.0" fallible-iterator = "0.2" -hmac = "0.11" -md-5 = "0.9" +hmac = "0.12" +md-5 = "0.10" memchr = "2.0" rand = "0.8" -sha2 = "0.9" +sha2 = "0.10" stringprep = "0.1" diff --git a/postgres-protocol/src/authentication/sasl.rs b/postgres-protocol/src/authentication/sasl.rs index a3704ce16..ea2f55cad 100644 --- a/postgres-protocol/src/authentication/sasl.rs +++ b/postgres-protocol/src/authentication/sasl.rs @@ -1,6 +1,6 @@ //! SASL-based authentication support. -use hmac::{Hmac, Mac, NewMac}; +use hmac::{Hmac, Mac}; use rand::{self, Rng}; use sha2::digest::FixedOutput; use sha2::{Digest, Sha256}; @@ -275,7 +275,7 @@ impl ScramSha256 { let mut hmac = Hmac::::new_from_slice(&server_key) .expect("HMAC is able to accept all key sizes"); hmac.update(auth_message.as_bytes()); - hmac.verify(&verifier) + hmac.verify_slice(&verifier) .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "SCRAM verification error")) } } diff --git a/postgres-protocol/src/password/mod.rs b/postgres-protocol/src/password/mod.rs index 1b32ae8f8..a60687bbe 100644 --- a/postgres-protocol/src/password/mod.rs +++ b/postgres-protocol/src/password/mod.rs @@ -7,7 +7,7 @@ //! end up in logs pg_stat displays, etc. use crate::authentication::sasl; -use hmac::{Hmac, Mac, NewMac}; +use hmac::{Hmac, Mac}; use md5::Md5; use rand::RngCore; use sha2::digest::FixedOutput; From 76cd380e5a70d76f4f73219385e906ea3d6be7f9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 8 Dec 2021 18:35:18 -0500 Subject: [PATCH 149/420] clippy --- tokio-postgres/src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index eb4e5bdc5..c026cca4f 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -780,7 +780,7 @@ impl<'a> UrlParser<'a> { } fn take_all(&mut self) -> &'a str { - mem::replace(&mut self.s, "") + mem::take(&mut self.s) } fn eat_byte(&mut self) { From 630f179892c9030119bf80df97aa05fef2dea525 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 10 Dec 2021 19:21:59 -0500 Subject: [PATCH 150/420] Release postgres-protocol v0.6.3 --- postgres-protocol/CHANGELOG.md | 6 ++++++ postgres-protocol/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres-protocol/CHANGELOG.md b/postgres-protocol/CHANGELOG.md index eb37f5883..5d9cecd01 100644 --- a/postgres-protocol/CHANGELOG.md +++ b/postgres-protocol/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.6.3 - 2021-12-10 + +### Changed + +* Upgraded `hmac`, `md-5` and `sha`. + ## v0.6.2 - 2021-09-29 ### Changed diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index 638778f22..2010e88ad 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-protocol" -version = "0.6.2" +version = "0.6.3" authors = ["Steven Fackler "] edition = "2018" description = "Low level Postgres protocol APIs" From c516805275aaaf106e8e512f53a9b0234f707583 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Thu, 16 Dec 2021 10:21:22 +0200 Subject: [PATCH 151/420] impl BorrowToSql for: - Box - Box --- postgres-types/src/lib.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 2a953db2f..010b06adc 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -1044,6 +1044,23 @@ impl BorrowToSql for &dyn ToSql { } } +impl sealed::Sealed for Box {} + +impl BorrowToSql for Box { + #[inline] + fn borrow_to_sql(&self) -> &dyn ToSql { + self.as_ref() + } +} + +impl sealed::Sealed for Box {} +impl BorrowToSql for Box { + #[inline] + fn borrow_to_sql(&self) -> &dyn ToSql { + self.as_ref() + } +} + impl sealed::Sealed for &(dyn ToSql + Sync) {} /// In async contexts it is sometimes necessary to have the additional From 35f4c0aeefef139e682ebead2db47397be513e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Obr=C3=A9jan?= Date: Sun, 26 Dec 2021 19:13:03 +0100 Subject: [PATCH 152/420] Implement `ToSql` & `FromSql` for `Box` --- postgres-types/src/lib.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 2a953db2f..84354cf3b 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -584,6 +584,18 @@ impl<'a> FromSql<'a> for String { } } +impl<'a> FromSql<'a> for Box { + fn from_sql(_: &Type, raw: &'a [u8]) -> Result, Box> { + types::text_from_sql(raw) + .map(ToString::to_string) + .map(String::into_boxed_str) + } + + fn accepts(ty: &Type) -> bool { + <&str as FromSql>::accepts(ty) + } +} + impl<'a> FromSql<'a> for &'a str { fn from_sql(_: &Type, raw: &'a [u8]) -> Result<&'a str, Box> { types::text_from_sql(raw) @@ -933,6 +945,18 @@ impl ToSql for String { to_sql_checked!(); } +impl ToSql for Box { + fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { + <&str as ToSql>::to_sql(&&**self, ty, w) + } + + fn accepts(ty: &Type) -> bool { + <&str as ToSql>::accepts(ty) + } + + to_sql_checked!(); +} + macro_rules! simple_to { ($t:ty, $f:ident, $($expected:ident),+) => { impl ToSql for $t { From 4561d44661d0367c5f7792eaf8086351b7eb673f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Obr=C3=A9jan?= Date: Sun, 26 Dec 2021 20:43:14 +0100 Subject: [PATCH 153/420] Add `#[postgres(transparent)]` --- .../src/compile-fail/invalid-transparent.rs | 35 ++++++ .../compile-fail/invalid-transparent.stderr | 49 ++++++++ postgres-derive-test/src/lib.rs | 1 + postgres-derive-test/src/transparent.rs | 18 +++ postgres-derive/src/accepts.rs | 8 ++ postgres-derive/src/fromsql.rs | 37 +++++- postgres-derive/src/lib.rs | 7 +- postgres-derive/src/overrides.rs | 20 +++- postgres-derive/src/tosql.rs | 107 ++++++++++++------ postgres-types/src/lib.rs | 15 +++ 10 files changed, 251 insertions(+), 46 deletions(-) create mode 100644 postgres-derive-test/src/compile-fail/invalid-transparent.rs create mode 100644 postgres-derive-test/src/compile-fail/invalid-transparent.stderr create mode 100644 postgres-derive-test/src/transparent.rs diff --git a/postgres-derive-test/src/compile-fail/invalid-transparent.rs b/postgres-derive-test/src/compile-fail/invalid-transparent.rs new file mode 100644 index 000000000..43bd48266 --- /dev/null +++ b/postgres-derive-test/src/compile-fail/invalid-transparent.rs @@ -0,0 +1,35 @@ +use postgres_types::{FromSql, ToSql}; + +#[derive(ToSql, Debug)] +#[postgres(transparent)] +struct ToSqlTransparentStruct { + a: i32 +} + +#[derive(FromSql, Debug)] +#[postgres(transparent)] +struct FromSqlTransparentStruct { + a: i32 +} + +#[derive(ToSql, Debug)] +#[postgres(transparent)] +enum ToSqlTransparentEnum { + Foo +} + +#[derive(FromSql, Debug)] +#[postgres(transparent)] +enum FromSqlTransparentEnum { + Foo +} + +#[derive(ToSql, Debug)] +#[postgres(transparent)] +struct ToSqlTransparentTwoFieldTupleStruct(i32, i32); + +#[derive(FromSql, Debug)] +#[postgres(transparent)] +struct FromSqlTransparentTwoFieldTupleStruct(i32, i32); + +fn main() {} diff --git a/postgres-derive-test/src/compile-fail/invalid-transparent.stderr b/postgres-derive-test/src/compile-fail/invalid-transparent.stderr new file mode 100644 index 000000000..42e49f874 --- /dev/null +++ b/postgres-derive-test/src/compile-fail/invalid-transparent.stderr @@ -0,0 +1,49 @@ +error: #[postgres(transparent)] may only be applied to single field tuple structs + --> src/compile-fail/invalid-transparent.rs:4:1 + | +4 | / #[postgres(transparent)] +5 | | struct ToSqlTransparentStruct { +6 | | a: i32 +7 | | } + | |_^ + +error: #[postgres(transparent)] may only be applied to single field tuple structs + --> src/compile-fail/invalid-transparent.rs:10:1 + | +10 | / #[postgres(transparent)] +11 | | struct FromSqlTransparentStruct { +12 | | a: i32 +13 | | } + | |_^ + +error: #[postgres(transparent)] may only be applied to single field tuple structs + --> src/compile-fail/invalid-transparent.rs:16:1 + | +16 | / #[postgres(transparent)] +17 | | enum ToSqlTransparentEnum { +18 | | Foo +19 | | } + | |_^ + +error: #[postgres(transparent)] may only be applied to single field tuple structs + --> src/compile-fail/invalid-transparent.rs:22:1 + | +22 | / #[postgres(transparent)] +23 | | enum FromSqlTransparentEnum { +24 | | Foo +25 | | } + | |_^ + +error: #[postgres(transparent)] may only be applied to single field tuple structs + --> src/compile-fail/invalid-transparent.rs:28:1 + | +28 | / #[postgres(transparent)] +29 | | struct ToSqlTransparentTwoFieldTupleStruct(i32, i32); + | |_____________________________________________________^ + +error: #[postgres(transparent)] may only be applied to single field tuple structs + --> src/compile-fail/invalid-transparent.rs:32:1 + | +32 | / #[postgres(transparent)] +33 | | struct FromSqlTransparentTwoFieldTupleStruct(i32, i32); + | |_______________________________________________________^ diff --git a/postgres-derive-test/src/lib.rs b/postgres-derive-test/src/lib.rs index 7da75af8f..279ed1419 100644 --- a/postgres-derive-test/src/lib.rs +++ b/postgres-derive-test/src/lib.rs @@ -7,6 +7,7 @@ use std::fmt; mod composites; mod domains; mod enums; +mod transparent; pub fn test_type(conn: &mut Client, sql_type: &str, checks: &[(T, S)]) where diff --git a/postgres-derive-test/src/transparent.rs b/postgres-derive-test/src/transparent.rs new file mode 100644 index 000000000..1614553d2 --- /dev/null +++ b/postgres-derive-test/src/transparent.rs @@ -0,0 +1,18 @@ +use postgres::{Client, NoTls}; +use postgres_types::{FromSql, ToSql}; + +#[test] +fn round_trip() { + #[derive(FromSql, ToSql, Debug, PartialEq)] + #[postgres(transparent)] + struct UserId(i32); + + assert_eq!( + Client::connect("user=postgres host=localhost port=5433", NoTls) + .unwrap() + .query_one("SELECT $1::integer", &[&UserId(123)]) + .unwrap() + .get::<_, UserId>(0), + UserId(123) + ); +} diff --git a/postgres-derive/src/accepts.rs b/postgres-derive/src/accepts.rs index 530badd0b..63473863a 100644 --- a/postgres-derive/src/accepts.rs +++ b/postgres-derive/src/accepts.rs @@ -6,6 +6,14 @@ use syn::Ident; use crate::composites::Field; use crate::enums::Variant; +pub fn transparent_body(field: &syn::Field) -> TokenStream { + let ty = &field.ty; + + quote! { + <#ty as ::postgres_types::ToSql>::accepts(type_) + } +} + pub fn domain_body(name: &str, field: &syn::Field) -> TokenStream { let ty = &field.ty; diff --git a/postgres-derive/src/fromsql.rs b/postgres-derive/src/fromsql.rs index 3a59d6226..c89cbb5e2 100644 --- a/postgres-derive/src/fromsql.rs +++ b/postgres-derive/src/fromsql.rs @@ -11,9 +11,36 @@ use crate::overrides::Overrides; pub fn expand_derive_fromsql(input: DeriveInput) -> Result { let overrides = Overrides::extract(&input.attrs)?; + if overrides.name.is_some() && overrides.transparent { + return Err(Error::new_spanned( + &input, + "#[postgres(transparent)] is not allowed with #[postgres(name = \"...\")]", + )); + } + let name = overrides.name.unwrap_or_else(|| input.ident.to_string()); - let (accepts_body, to_sql_body) = match input.data { + let (accepts_body, to_sql_body) = if overrides.transparent { + match input.data { + Data::Struct(DataStruct { + fields: Fields::Unnamed(ref fields), + .. + }) if fields.unnamed.len() == 1 => { + let field = fields.unnamed.first().unwrap(); + ( + accepts::transparent_body(field), + transparent_body(&input.ident, field), + ) + } + _ => { + return Err(Error::new_spanned( + input, + "#[postgres(transparent)] may only be applied to single field tuple structs", + )) + } + } + } else { + match input.data { Data::Enum(ref data) => { let variants = data .variants @@ -55,6 +82,7 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result { "#[derive(FromSql)] may only be applied to structs, single field tuple structs, and enums", )) } + } }; let ident = &input.ident; @@ -77,6 +105,13 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result { Ok(out) } +fn transparent_body(ident: &Ident, field: &syn::Field) -> TokenStream { + let ty = &field.ty; + quote! { + <#ty as postgres_types::FromSql>::from_sql(_type, buf).map(#ident) + } +} + fn enum_body(ident: &Ident, variants: &[Variant]) -> TokenStream { let variant_names = variants.iter().map(|v| &v.name); let idents = iter::repeat(ident); diff --git a/postgres-derive/src/lib.rs b/postgres-derive/src/lib.rs index fd17b9de6..98e6add24 100644 --- a/postgres-derive/src/lib.rs +++ b/postgres-derive/src/lib.rs @@ -4,6 +4,7 @@ extern crate proc_macro; use proc_macro::TokenStream; +use syn::parse_macro_input; mod accepts; mod composites; @@ -14,7 +15,8 @@ mod tosql; #[proc_macro_derive(ToSql, attributes(postgres))] pub fn derive_tosql(input: TokenStream) -> TokenStream { - let input = syn::parse(input).unwrap(); + let input = parse_macro_input!(input); + tosql::expand_derive_tosql(input) .unwrap_or_else(|e| e.to_compile_error()) .into() @@ -22,7 +24,8 @@ pub fn derive_tosql(input: TokenStream) -> TokenStream { #[proc_macro_derive(FromSql, attributes(postgres))] pub fn derive_fromsql(input: TokenStream) -> TokenStream { - let input = syn::parse(input).unwrap(); + let input = parse_macro_input!(input); + fromsql::expand_derive_fromsql(input) .unwrap_or_else(|e| e.to_compile_error()) .into() diff --git a/postgres-derive/src/overrides.rs b/postgres-derive/src/overrides.rs index 08e6f3a77..c00d5a94b 100644 --- a/postgres-derive/src/overrides.rs +++ b/postgres-derive/src/overrides.rs @@ -2,17 +2,18 @@ use syn::{Attribute, Error, Lit, Meta, NestedMeta}; pub struct Overrides { pub name: Option, + pub transparent: bool, } impl Overrides { pub fn extract(attrs: &[Attribute]) -> Result { - let mut overrides = Overrides { name: None }; + let mut overrides = Overrides { + name: None, + transparent: false, + }; for attr in attrs { - let attr = match attr.parse_meta() { - Ok(meta) => meta, - Err(_) => continue, - }; + let attr = attr.parse_meta()?; if !attr.path().is_ident("postgres") { continue; @@ -39,7 +40,14 @@ impl Overrides { overrides.name = Some(value); } - bad => return Err(Error::new_spanned(bad, "expected a name-value meta item")), + NestedMeta::Meta(Meta::Path(ref path)) => { + if !path.is_ident("transparent") { + return Err(Error::new_spanned(path, "unknown override")); + } + + overrides.transparent = true; + } + bad => return Err(Error::new_spanned(bad, "unknown attribute")), } } } diff --git a/postgres-derive/src/tosql.rs b/postgres-derive/src/tosql.rs index 1808e787d..96f261385 100644 --- a/postgres-derive/src/tosql.rs +++ b/postgres-derive/src/tosql.rs @@ -11,46 +11,73 @@ use crate::overrides::Overrides; pub fn expand_derive_tosql(input: DeriveInput) -> Result { let overrides = Overrides::extract(&input.attrs)?; + if overrides.name.is_some() && overrides.transparent { + return Err(Error::new_spanned( + &input, + "#[postgres(transparent)] is not allowed with #[postgres(name = \"...\")]", + )); + } + let name = overrides.name.unwrap_or_else(|| input.ident.to_string()); - let (accepts_body, to_sql_body) = match input.data { - Data::Enum(ref data) => { - let variants = data - .variants - .iter() - .map(Variant::parse) - .collect::, _>>()?; - ( - accepts::enum_body(&name, &variants), - enum_body(&input.ident, &variants), - ) - } - Data::Struct(DataStruct { - fields: Fields::Unnamed(ref fields), - .. - }) if fields.unnamed.len() == 1 => { - let field = fields.unnamed.first().unwrap(); - (accepts::domain_body(&name, field), domain_body()) - } - Data::Struct(DataStruct { - fields: Fields::Named(ref fields), - .. - }) => { - let fields = fields - .named - .iter() - .map(Field::parse) - .collect::, _>>()?; - ( - accepts::composite_body(&name, "ToSql", &fields), - composite_body(&fields), - ) + let (accepts_body, to_sql_body) = if overrides.transparent { + match input.data { + Data::Struct(DataStruct { + fields: Fields::Unnamed(ref fields), + .. + }) if fields.unnamed.len() == 1 => { + let field = fields.unnamed.first().unwrap(); + + (accepts::transparent_body(field), transparent_body()) + } + _ => { + return Err(Error::new_spanned( + input, + "#[postgres(transparent)] may only be applied to single field tuple structs", + )); + } } - _ => { - return Err(Error::new_spanned( - input, - "#[derive(ToSql)] may only be applied to structs, single field tuple structs, and enums", - )); + } else { + match input.data { + Data::Enum(ref data) => { + let variants = data + .variants + .iter() + .map(Variant::parse) + .collect::, _>>()?; + ( + accepts::enum_body(&name, &variants), + enum_body(&input.ident, &variants), + ) + } + Data::Struct(DataStruct { + fields: Fields::Unnamed(ref fields), + .. + }) if fields.unnamed.len() == 1 => { + let field = fields.unnamed.first().unwrap(); + + (accepts::domain_body(&name, field), domain_body()) + } + Data::Struct(DataStruct { + fields: Fields::Named(ref fields), + .. + }) => { + let fields = fields + .named + .iter() + .map(Field::parse) + .collect::, _>>()?; + ( + accepts::composite_body(&name, "ToSql", &fields), + composite_body(&fields), + ) + } + _ => { + return Err(Error::new_spanned( + input, + "#[derive(ToSql)] may only be applied to structs, single field tuple structs, and enums", + )); + } } }; @@ -78,6 +105,12 @@ pub fn expand_derive_tosql(input: DeriveInput) -> Result { Ok(out) } +fn transparent_body() -> TokenStream { + quote! { + postgres_types::ToSql::to_sql(&self.0, _type, buf) + } +} + fn enum_body(ident: &Ident, variants: &[Variant]) -> TokenStream { let idents = iter::repeat(ident); let variant_idents = variants.iter().map(|v| &v.ident); diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 2a953db2f..e409051e8 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -55,6 +55,21 @@ //! struct SessionId(Vec); //! ``` //! +//! ## Newtypes +//! +//! The `#[postgres(transparent)]` attribute can be used on a single-field tuple struct to create a +//! Rust-only wrapper type that will use the [`ToSql`] & [`FromSql`] implementation of the inner +//! value : +//! ```rust +//! # #[cfg(feature = "derive")] +//! use postgres_types::{ToSql, FromSql}; +//! +//! # #[cfg(feature = "derive")] +//! #[derive(Debug, ToSql, FromSql)] +//! #[postgres(transparent)] +//! struct UserId(i32); +//! ``` +//! //! ## Composites //! //! Postgres composite types correspond to structs in Rust: From 842e5cfdcb2c3f4fec3d394ccd1e8b91e2e8985b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Jan 2022 13:15:32 +0000 Subject: [PATCH 154/420] Update parking_lot requirement from 0.11 to 0.12 Updates the requirements on [parking_lot](https://github.com/Amanieu/parking_lot) to permit the latest version. - [Release notes](https://github.com/Amanieu/parking_lot/releases) - [Changelog](https://github.com/Amanieu/parking_lot/blob/master/CHANGELOG.md) - [Commits](https://github.com/Amanieu/parking_lot/compare/0.11.0...0.12.0) --- updated-dependencies: - dependency-name: parking_lot dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- tokio-postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 5974fe64f..7d898e269 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -46,7 +46,7 @@ byteorder = "1.0" fallible-iterator = "0.2" futures = "0.3" log = "0.4" -parking_lot = "0.11" +parking_lot = "0.12" percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.10" From a07a39cc875b95565908125d66c1dfb6682d406a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 31 Jan 2022 09:11:29 -0500 Subject: [PATCH 155/420] Update ci.yml --- .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 e38dea88d..520d665f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: - run: docker compose up -d - uses: sfackler/actions/rustup@master with: - version: 1.51.0 + version: 1.53.0 - run: echo "::set-output name=version::$(rustc --version)" id: rust-version - uses: actions/cache@v1 From 7fd748ba96d3056a1a2315799661d7e9e849deb7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Feb 2022 13:47:41 +0000 Subject: [PATCH 156/420] Update tokio-util requirement from 0.6 to 0.7 Updates the requirements on [tokio-util](https://github.com/tokio-rs/tokio) to permit the latest version. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/commits) --- updated-dependencies: - dependency-name: tokio-util dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- tokio-postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 7d898e269..94371af51 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -54,7 +54,7 @@ postgres-protocol = { version = "0.6.1", path = "../postgres-protocol" } postgres-types = { version = "0.2.2", path = "../postgres-types" } socket2 = "0.4" tokio = { version = "1.0", features = ["io-util"] } -tokio-util = { version = "0.6", features = ["codec"] } +tokio-util = { version = "0.7", features = ["codec"] } [dev-dependencies] tokio = { version = "1.0", features = ["full"] } From 9685f9c532f10bd99339e2dcddaad3b462c5b687 Mon Sep 17 00:00:00 2001 From: Tim Anderson Date: Wed, 16 Mar 2022 14:13:36 +1000 Subject: [PATCH 157/420] Add ToSql / FromSql for IpInet and IpCidr from cidr crate --- postgres-types/Cargo.toml | 2 ++ postgres-types/src/cidr_02.rs | 44 +++++++++++++++++++++++++++++++++++ postgres-types/src/lib.rs | 2 ++ 3 files changed, 48 insertions(+) create mode 100644 postgres-types/src/cidr_02.rs diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 7eca3fbcf..1954d51bb 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -14,6 +14,7 @@ categories = ["database"] derive = ["postgres-derive"] array-impls = ["array-init"] with-bit-vec-0_6 = ["bit-vec-06"] +with-cidr-0_2 = ["cidr-02"] with-chrono-0_4 = ["chrono-04"] with-eui48-0_4 = ["eui48-04"] with-eui48-1 = ["eui48-1"] @@ -32,6 +33,7 @@ postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-deri array-init = { version = "2", optional = true } bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } +cidr-02 = { version = "0.2", package = "cidr", optional = true } chrono-04 = { version = "0.4.16", package = "chrono", default-features = false, features = ["clock"], optional = true } eui48-04 = { version = "0.4", package = "eui48", optional = true } eui48-1 = { version = "1.0", package = "eui48", optional = true } diff --git a/postgres-types/src/cidr_02.rs b/postgres-types/src/cidr_02.rs new file mode 100644 index 000000000..46e904483 --- /dev/null +++ b/postgres-types/src/cidr_02.rs @@ -0,0 +1,44 @@ +use bytes::BytesMut; +use cidr_02::{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()).expect("postgres cidr type has zeroed host portion")) + } + + 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()).expect("postgres enforces maximum length of 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 0247b90b7..b1a45bab1 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -210,6 +210,8 @@ where #[cfg(feature = "with-bit-vec-0_6")] mod bit_vec_06; +#[cfg(feature = "with-cidr-0_2")] +mod cidr_02; #[cfg(feature = "with-chrono-0_4")] mod chrono_04; #[cfg(feature = "with-eui48-0_4")] From dd7bc073f7a7dfd1a1dd9c3e90e5d9d1630a2824 Mon Sep 17 00:00:00 2001 From: Tim Anderson Date: Wed, 16 Mar 2022 14:32:50 +1000 Subject: [PATCH 158/420] Document cidr type conversion and run rustfmt --- postgres-types/Cargo.toml | 2 +- postgres-types/src/cidr_02.rs | 6 ++++-- postgres-types/src/lib.rs | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 1954d51bb..9d470f37b 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -33,8 +33,8 @@ postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-deri array-init = { version = "2", optional = true } bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } -cidr-02 = { version = "0.2", package = "cidr", optional = true } chrono-04 = { version = "0.4.16", package = "chrono", default-features = false, features = ["clock"], optional = true } +cidr-02 = { version = "0.2", package = "cidr", optional = true } eui48-04 = { version = "0.4", package = "eui48", optional = true } eui48-1 = { version = "1.0", package = "eui48", optional = true } geo-types-06 = { version = "0.6", package = "geo-types", optional = true } diff --git a/postgres-types/src/cidr_02.rs b/postgres-types/src/cidr_02.rs index 46e904483..d4e4965c5 100644 --- a/postgres-types/src/cidr_02.rs +++ b/postgres-types/src/cidr_02.rs @@ -8,7 +8,8 @@ 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()).expect("postgres cidr type has zeroed host portion")) + Ok(IpCidr::new(inet.addr(), inet.netmask()) + .expect("postgres cidr type has zeroed host portion")) } accepts!(CIDR); @@ -27,7 +28,8 @@ impl ToSql for IpCidr { 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()).expect("postgres enforces maximum length of netmask")) + Ok(IpInet::new(inet.addr(), inet.netmask()) + .expect("postgres enforces maximum length of netmask")) } accepts!(INET); diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index b1a45bab1..394f938ff 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -210,10 +210,10 @@ where #[cfg(feature = "with-bit-vec-0_6")] mod bit_vec_06; -#[cfg(feature = "with-cidr-0_2")] -mod cidr_02; #[cfg(feature = "with-chrono-0_4")] mod chrono_04; +#[cfg(feature = "with-cidr-0_2")] +mod cidr_02; #[cfg(feature = "with-eui48-0_4")] mod eui48_04; #[cfg(feature = "with-eui48-1")] @@ -438,6 +438,8 @@ impl WrongType { /// | `uuid::Uuid` | UUID | /// | `bit_vec::BitVec` | BIT, VARBIT | /// | `eui48::MacAddress` | MACADDR | +/// | `cidr::InetCidr` | CIDR | +/// | `cidr::InetAddr` | INET | /// /// # Nullability /// From 27039f6c3a9f05a41b657f1db5489d055363e2a8 Mon Sep 17 00:00:00 2001 From: Tim Anderson Date: Thu, 17 Mar 2022 09:31:13 +1000 Subject: [PATCH 159/420] Change error handling in `cidr` `FromSql` implementations --- postgres-types/src/cidr_02.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/postgres-types/src/cidr_02.rs b/postgres-types/src/cidr_02.rs index d4e4965c5..2de952c3c 100644 --- a/postgres-types/src/cidr_02.rs +++ b/postgres-types/src/cidr_02.rs @@ -8,8 +8,7 @@ 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()) - .expect("postgres cidr type has zeroed host portion")) + Ok(IpCidr::new(inet.addr(), inet.netmask())?) } accepts!(CIDR); @@ -28,8 +27,7 @@ impl ToSql for IpCidr { 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()) - .expect("postgres enforces maximum length of netmask")) + Ok(IpInet::new(inet.addr(), inet.netmask())?) } accepts!(INET); From 944b72974f751ecd6ac72447af753cec7b88320e Mon Sep 17 00:00:00 2001 From: Matt Oliver Date: Thu, 3 Mar 2022 00:06:46 -0600 Subject: [PATCH 160/420] Add ltree, lquery and ltxtquery support --- postgres-protocol/Cargo.toml | 2 +- postgres-protocol/src/types/mod.rs | 16 ++++++ postgres-types/Cargo.toml | 4 +- postgres-types/src/lib.rs | 44 +++++++++++---- tokio-postgres/Cargo.toml | 6 +-- tokio-postgres/tests/test/types/mod.rs | 75 ++++++++++++++++++++++++++ 6 files changed, 131 insertions(+), 16 deletions(-) diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index 2010e88ad..a4716907b 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-protocol" -version = "0.6.3" +version = "0.6.4" authors = ["Steven Fackler "] edition = "2018" description = "Low level Postgres protocol APIs" diff --git a/postgres-protocol/src/types/mod.rs b/postgres-protocol/src/types/mod.rs index a595f5a30..5939d9f00 100644 --- a/postgres-protocol/src/types/mod.rs +++ b/postgres-protocol/src/types/mod.rs @@ -1059,3 +1059,19 @@ impl Inet { self.netmask } } + +/// Serializes a Postgres l{tree,query,txtquery} string +#[inline] +pub fn ltree_to_sql(v: &str, buf: &mut BytesMut) { + // A version number is prepended to an Ltree string per spec + buf.put_u8(1); + // Append the rest of the query + buf.put_slice(v.as_bytes()); +} + +/// Deserialize a Postgres l{tree,query,txtquery} string +#[inline] +pub fn ltree_from_sql(buf: &[u8]) -> Result<&str, StdBox> { + // Remove the version number from the front of the string per spec + Ok(str::from_utf8(&buf[1..])?) +} diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 9d470f37b..000d71ea0 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-types" -version = "0.2.2" +version = "0.2.3" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -28,7 +28,7 @@ with-time-0_3 = ["time-03"] [dependencies] bytes = "1.0" fallible-iterator = "0.2" -postgres-protocol = { version = "0.6.1", path = "../postgres-protocol" } +postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" } postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-derive" } array-init = { version = "2", optional = true } diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 394f938ff..bf7a1caee 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -594,8 +594,8 @@ impl<'a> FromSql<'a> for &'a [u8] { } impl<'a> FromSql<'a> for String { - fn from_sql(_: &Type, raw: &'a [u8]) -> Result> { - types::text_from_sql(raw).map(ToString::to_string) + fn from_sql(ty: &Type, raw: &'a [u8]) -> Result> { + <&str as FromSql>::from_sql(ty, raw).map(ToString::to_string) } fn accepts(ty: &Type) -> bool { @@ -604,8 +604,8 @@ impl<'a> FromSql<'a> for String { } impl<'a> FromSql<'a> for Box { - fn from_sql(_: &Type, raw: &'a [u8]) -> Result, Box> { - types::text_from_sql(raw) + fn from_sql(ty: &Type, raw: &'a [u8]) -> Result, Box> { + <&str as FromSql>::from_sql(ty, raw) .map(ToString::to_string) .map(String::into_boxed_str) } @@ -616,14 +616,26 @@ impl<'a> FromSql<'a> for Box { } impl<'a> FromSql<'a> for &'a str { - fn from_sql(_: &Type, raw: &'a [u8]) -> Result<&'a str, Box> { - types::text_from_sql(raw) + fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<&'a str, Box> { + match *ty { + ref ty if ( + ty.name() == "ltree" || + ty.name() == "lquery" || + ty.name() == "ltxtquery" + ) => types::ltree_from_sql(raw), + _ => types::text_from_sql(raw) + } } fn accepts(ty: &Type) -> bool { match *ty { Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true, - ref ty if ty.name() == "citext" => true, + ref ty if ( + ty.name() == "citext" || + ty.name() == "ltree" || + ty.name() == "lquery" || + ty.name() == "ltxtquery" + ) => true, _ => false, } } @@ -924,15 +936,27 @@ impl ToSql for Vec { } impl<'a> ToSql for &'a str { - fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { - types::text_to_sql(*self, w); + fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { + match ty { + ref ty if ( + ty.name() == "ltree" || + ty.name() == "lquery" || + ty.name() == "ltxtquery" + ) => types::ltree_to_sql(*self, w), + _ => types::text_to_sql(*self, w) + } Ok(IsNull::No) } fn accepts(ty: &Type) -> bool { match *ty { Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true, - ref ty if ty.name() == "citext" => true, + ref ty if ( + ty.name() == "citext" || + ty.name() == "ltree" || + ty.name() == "lquery" || + ty.name() == "ltxtquery" + ) => true, _ => false, } } diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 94371af51..82e71fb1c 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.7.5" +version = "0.7.6" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -50,8 +50,8 @@ parking_lot = "0.12" percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.10" -postgres-protocol = { version = "0.6.1", path = "../postgres-protocol" } -postgres-types = { version = "0.2.2", path = "../postgres-types" } +postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" } +postgres-types = { version = "0.2.3", path = "../postgres-types" } socket2 = "0.4" tokio = { version = "1.0", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index 604e2de32..0ec329a4f 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -648,3 +648,78 @@ async fn inet() { ) .await; } + +#[tokio::test] +async fn ltree() { + let client = connect("user=postgres").await; + client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap(); + + test_type("ltree", &[ + (Some("b.c.d".to_owned()), "'b.c.d'"), + (None, "NULL"), + ]).await; +} + +#[tokio::test] +async fn ltree_any() { + let client = connect("user=postgres").await; + client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap(); + + test_type("ltree[]", &[ + (Some(vec![]), "ARRAY[]"), + (Some(vec!["a.b.c".to_string()]), "ARRAY['a.b.c']"), + (Some(vec!["a.b.c".to_string(), "e.f.g".to_string()]), "ARRAY['a.b.c','e.f.g']"), + (None, "NULL"), + ]).await; +} + +#[tokio::test] +async fn lquery() { + let client = connect("user=postgres").await; + client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap(); + + test_type("lquery", &[ + (Some("b.c.d".to_owned()), "'b.c.d'"), + (Some("b.c.*".to_owned()), "'b.c.*'"), + (Some("b.*{1,2}.d|e".to_owned()), "'b.*{1,2}.d|e'"), + (None, "NULL"), + ]).await; +} + +#[tokio::test] +async fn lquery_any() { + let client = connect("user=postgres").await; + client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap(); + + test_type("lquery[]", &[ + (Some(vec![]), "ARRAY[]"), + (Some(vec!["b.c.*".to_string()]), "ARRAY['b.c.*']"), + (Some(vec!["b.c.*".to_string(), "b.*{1,2}.d|e".to_string()]), "ARRAY['b.c.*','b.*{1,2}.d|e']"), + (None, "NULL"), + ]).await; +} + +#[tokio::test] +async fn ltxtquery() { + let client = connect("user=postgres").await; + client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap(); + + test_type("ltxtquery", &[ + (Some("b & c & d".to_owned()), "'b & c & d'"), + (Some("b@* & !c".to_owned()), "'b@* & !c'"), + (None, "NULL"), + ]).await; +} + +#[tokio::test] +async fn ltxtquery_any() { + let client = connect("user=postgres").await; + client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap(); + + test_type("ltxtquery[]", &[ + (Some(vec![]), "ARRAY[]"), + (Some(vec!["b & c & d".to_string()]), "ARRAY['b & c & d']"), + (Some(vec!["b & c & d".to_string(), "b@* & !c".to_string()]), "ARRAY['b & c & d','b@* & !c']"), + (None, "NULL"), + ]).await; +} From 6ae60d6d09cb32eb8eca645488e5d86d4f2a33bb Mon Sep 17 00:00:00 2001 From: Matt Oliver Date: Thu, 3 Mar 2022 08:20:29 -0600 Subject: [PATCH 161/420] Add types to type docs --- postgres-types/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index bf7a1caee..9580fb5c1 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -407,6 +407,7 @@ impl WrongType { /// | `f32` | REAL | /// | `f64` | DOUBLE PRECISION | /// | `&str`/`String` | VARCHAR, CHAR(n), TEXT, CITEXT, NAME, UNKNOWN | +/// | | LTREE, LQUERY, LTXTQUERY | /// | `&[u8]`/`Vec` | BYTEA | /// | `HashMap>` | HSTORE | /// | `SystemTime` | TIMESTAMP, TIMESTAMP WITH TIME ZONE | @@ -739,6 +740,7 @@ pub enum IsNull { /// | `f32` | REAL | /// | `f64` | DOUBLE PRECISION | /// | `&str`/`String` | VARCHAR, CHAR(n), TEXT, CITEXT, NAME | +/// | | LTREE, LQUERY, LTXTQUERY | /// | `&[u8]`/`Vec` | BYTEA | /// | `HashMap>` | HSTORE | /// | `SystemTime` | TIMESTAMP, TIMESTAMP WITH TIME ZONE | From d9d283e131e3577bd82b292bbc8fa045c70e98fa Mon Sep 17 00:00:00 2001 From: Matt Oliver Date: Sat, 5 Mar 2022 14:55:07 -0600 Subject: [PATCH 162/420] Split out ltree,query,txtquery protocol parsers, add tests, rust fmt --- postgres-protocol/src/types/mod.rs | 51 +++++++++- postgres-protocol/src/types/test.rs | 116 +++++++++++++++++++++- postgres-types/src/lib.rs | 50 +++++----- tokio-postgres/tests/test/types/mod.rs | 128 +++++++++++++++++-------- 4 files changed, 274 insertions(+), 71 deletions(-) diff --git a/postgres-protocol/src/types/mod.rs b/postgres-protocol/src/types/mod.rs index 5939d9f00..05f515f76 100644 --- a/postgres-protocol/src/types/mod.rs +++ b/postgres-protocol/src/types/mod.rs @@ -1060,18 +1060,59 @@ impl Inet { } } -/// Serializes a Postgres l{tree,query,txtquery} string +/// Serializes a Postgres ltree string #[inline] pub fn ltree_to_sql(v: &str, buf: &mut BytesMut) { - // A version number is prepended to an Ltree string per spec + // A version number is prepended to an ltree string per spec buf.put_u8(1); // Append the rest of the query buf.put_slice(v.as_bytes()); } -/// Deserialize a Postgres l{tree,query,txtquery} string +/// Deserialize a Postgres ltree string #[inline] pub fn ltree_from_sql(buf: &[u8]) -> Result<&str, StdBox> { - // Remove the version number from the front of the string per spec - Ok(str::from_utf8(&buf[1..])?) + match buf { + // Remove the version number from the front of the ltree per spec + [1u8, rest @ ..] => Ok(str::from_utf8(rest)?), + _ => Err("ltree version 1 only supported".into()), + } +} + +/// Serializes a Postgres lquery string +#[inline] +pub fn lquery_to_sql(v: &str, buf: &mut BytesMut) { + // A version number is prepended to an lquery string per spec + buf.put_u8(1); + // Append the rest of the query + buf.put_slice(v.as_bytes()); +} + +/// Deserialize a Postgres lquery string +#[inline] +pub fn lquery_from_sql(buf: &[u8]) -> Result<&str, StdBox> { + match buf { + // Remove the version number from the front of the lquery per spec + [1u8, rest @ ..] => Ok(str::from_utf8(rest)?), + _ => Err("lquery version 1 only supported".into()), + } +} + +/// Serializes a Postgres ltxtquery string +#[inline] +pub fn ltxtquery_to_sql(v: &str, buf: &mut BytesMut) { + // A version number is prepended to an ltxtquery string per spec + buf.put_u8(1); + // Append the rest of the query + buf.put_slice(v.as_bytes()); +} + +/// Deserialize a Postgres ltxtquery string +#[inline] +pub fn ltxtquery_from_sql(buf: &[u8]) -> Result<&str, StdBox> { + match buf { + // Remove the version number from the front of the ltxtquery per spec + [1u8, rest @ ..] => Ok(str::from_utf8(rest)?), + _ => Err("ltxtquery version 1 only supported".into()), + } } diff --git a/postgres-protocol/src/types/test.rs b/postgres-protocol/src/types/test.rs index 7c20cf3ed..1ce49b66f 100644 --- a/postgres-protocol/src/types/test.rs +++ b/postgres-protocol/src/types/test.rs @@ -1,4 +1,4 @@ -use bytes::BytesMut; +use bytes::{Buf, BytesMut}; use fallible_iterator::FallibleIterator; use std::collections::HashMap; @@ -156,3 +156,117 @@ fn non_null_array() { assert_eq!(array.dimensions().collect::>().unwrap(), dimensions); assert_eq!(array.values().collect::>().unwrap(), values); } + +#[test] +fn ltree_sql() { + let mut query = vec![1u8]; + query.extend_from_slice("A.B.C".as_bytes()); + + let mut buf = BytesMut::new(); + + ltree_to_sql("A.B.C", &mut buf); + + assert_eq!(query.as_slice(), buf.chunk()); +} + +#[test] +fn ltree_str() { + let mut query = vec![1u8]; + query.extend_from_slice("A.B.C".as_bytes()); + + let success = match ltree_from_sql(query.as_slice()) { + Ok(_) => true, + _ => false, + }; + + assert!(success) +} + +#[test] +fn ltree_wrong_version() { + let mut query = vec![2u8]; + query.extend_from_slice("A.B.C".as_bytes()); + + let success = match ltree_from_sql(query.as_slice()) { + Err(_) => true, + _ => false, + }; + + assert!(success) +} + +#[test] +fn lquery_sql() { + let mut query = vec![1u8]; + query.extend_from_slice("A.B.C".as_bytes()); + + let mut buf = BytesMut::new(); + + lquery_to_sql("A.B.C", &mut buf); + + assert_eq!(query.as_slice(), buf.chunk()); +} + +#[test] +fn lquery_str() { + let mut query = vec![1u8]; + query.extend_from_slice("A.B.C".as_bytes()); + + let success = match lquery_from_sql(query.as_slice()) { + Ok(_) => true, + _ => false, + }; + + assert!(success) +} + +#[test] +fn lquery_wrong_version() { + let mut query = vec![2u8]; + query.extend_from_slice("A.B.C".as_bytes()); + + let success = match lquery_from_sql(query.as_slice()) { + Err(_) => true, + _ => false, + }; + + assert!(success) +} + +#[test] +fn ltxtquery_sql() { + let mut query = vec![1u8]; + query.extend_from_slice("a & b*".as_bytes()); + + let mut buf = BytesMut::new(); + + ltree_to_sql("a & b*", &mut buf); + + assert_eq!(query.as_slice(), buf.chunk()); +} + +#[test] +fn ltxtquery_str() { + let mut query = vec![1u8]; + query.extend_from_slice("a & b*".as_bytes()); + + let success = match ltree_from_sql(query.as_slice()) { + Ok(_) => true, + _ => false, + }; + + assert!(success) +} + +#[test] +fn ltxtquery_wrong_version() { + let mut query = vec![2u8]; + query.extend_from_slice("a & b*".as_bytes()); + + let success = match ltree_from_sql(query.as_slice()) { + Err(_) => true, + _ => false, + }; + + assert!(success) +} diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 9580fb5c1..d029d3948 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -619,24 +619,24 @@ impl<'a> FromSql<'a> for Box { impl<'a> FromSql<'a> for &'a str { fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<&'a str, Box> { match *ty { - ref ty if ( - ty.name() == "ltree" || - ty.name() == "lquery" || - ty.name() == "ltxtquery" - ) => types::ltree_from_sql(raw), - _ => types::text_from_sql(raw) + ref ty if ty.name() == "ltree" => types::ltree_from_sql(raw), + ref ty if ty.name() == "lquery" => types::lquery_from_sql(raw), + ref ty if ty.name() == "ltxtquery" => types::ltxtquery_from_sql(raw), + _ => types::text_from_sql(raw), } } fn accepts(ty: &Type) -> bool { match *ty { Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true, - ref ty if ( - ty.name() == "citext" || - ty.name() == "ltree" || - ty.name() == "lquery" || - ty.name() == "ltxtquery" - ) => true, + ref ty + if (ty.name() == "citext" + || ty.name() == "ltree" + || ty.name() == "lquery" + || ty.name() == "ltxtquery") => + { + true + } _ => false, } } @@ -939,13 +939,11 @@ impl ToSql for Vec { impl<'a> ToSql for &'a str { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { - match ty { - ref ty if ( - ty.name() == "ltree" || - ty.name() == "lquery" || - ty.name() == "ltxtquery" - ) => types::ltree_to_sql(*self, w), - _ => types::text_to_sql(*self, w) + match *ty { + ref ty if ty.name() == "ltree" => types::ltree_to_sql(*self, w), + ref ty if ty.name() == "lquery" => types::lquery_to_sql(*self, w), + ref ty if ty.name() == "ltxtquery" => types::ltxtquery_to_sql(*self, w), + _ => types::text_to_sql(*self, w), } Ok(IsNull::No) } @@ -953,12 +951,14 @@ impl<'a> ToSql for &'a str { fn accepts(ty: &Type) -> bool { match *ty { Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true, - ref ty if ( - ty.name() == "citext" || - ty.name() == "ltree" || - ty.name() == "lquery" || - ty.name() == "ltxtquery" - ) => true, + ref ty + if (ty.name() == "citext" + || ty.name() == "ltree" + || ty.name() == "lquery" + || ty.name() == "ltxtquery") => + { + true + } _ => false, } } diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index 0ec329a4f..f69932e55 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -652,74 +652,122 @@ async fn inet() { #[tokio::test] async fn ltree() { let client = connect("user=postgres").await; - client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap(); + client + .execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]) + .await + .unwrap(); - test_type("ltree", &[ - (Some("b.c.d".to_owned()), "'b.c.d'"), - (None, "NULL"), - ]).await; + test_type( + "ltree", + &[(Some("b.c.d".to_owned()), "'b.c.d'"), (None, "NULL")], + ) + .await; } #[tokio::test] async fn ltree_any() { let client = connect("user=postgres").await; - client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap(); + client + .execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]) + .await + .unwrap(); - test_type("ltree[]", &[ - (Some(vec![]), "ARRAY[]"), - (Some(vec!["a.b.c".to_string()]), "ARRAY['a.b.c']"), - (Some(vec!["a.b.c".to_string(), "e.f.g".to_string()]), "ARRAY['a.b.c','e.f.g']"), - (None, "NULL"), - ]).await; + test_type( + "ltree[]", + &[ + (Some(vec![]), "ARRAY[]"), + (Some(vec!["a.b.c".to_string()]), "ARRAY['a.b.c']"), + ( + Some(vec!["a.b.c".to_string(), "e.f.g".to_string()]), + "ARRAY['a.b.c','e.f.g']", + ), + (None, "NULL"), + ], + ) + .await; } #[tokio::test] async fn lquery() { let client = connect("user=postgres").await; - client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap(); + client + .execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]) + .await + .unwrap(); - test_type("lquery", &[ - (Some("b.c.d".to_owned()), "'b.c.d'"), - (Some("b.c.*".to_owned()), "'b.c.*'"), - (Some("b.*{1,2}.d|e".to_owned()), "'b.*{1,2}.d|e'"), - (None, "NULL"), - ]).await; + test_type( + "lquery", + &[ + (Some("b.c.d".to_owned()), "'b.c.d'"), + (Some("b.c.*".to_owned()), "'b.c.*'"), + (Some("b.*{1,2}.d|e".to_owned()), "'b.*{1,2}.d|e'"), + (None, "NULL"), + ], + ) + .await; } #[tokio::test] async fn lquery_any() { let client = connect("user=postgres").await; - client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap(); + client + .execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]) + .await + .unwrap(); - test_type("lquery[]", &[ - (Some(vec![]), "ARRAY[]"), - (Some(vec!["b.c.*".to_string()]), "ARRAY['b.c.*']"), - (Some(vec!["b.c.*".to_string(), "b.*{1,2}.d|e".to_string()]), "ARRAY['b.c.*','b.*{1,2}.d|e']"), - (None, "NULL"), - ]).await; + test_type( + "lquery[]", + &[ + (Some(vec![]), "ARRAY[]"), + (Some(vec!["b.c.*".to_string()]), "ARRAY['b.c.*']"), + ( + Some(vec!["b.c.*".to_string(), "b.*{1,2}.d|e".to_string()]), + "ARRAY['b.c.*','b.*{1,2}.d|e']", + ), + (None, "NULL"), + ], + ) + .await; } #[tokio::test] async fn ltxtquery() { let client = connect("user=postgres").await; - client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap(); + client + .execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]) + .await + .unwrap(); - test_type("ltxtquery", &[ - (Some("b & c & d".to_owned()), "'b & c & d'"), - (Some("b@* & !c".to_owned()), "'b@* & !c'"), - (None, "NULL"), - ]).await; + test_type( + "ltxtquery", + &[ + (Some("b & c & d".to_owned()), "'b & c & d'"), + (Some("b@* & !c".to_owned()), "'b@* & !c'"), + (None, "NULL"), + ], + ) + .await; } #[tokio::test] async fn ltxtquery_any() { let client = connect("user=postgres").await; - client.execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]).await.unwrap(); - - test_type("ltxtquery[]", &[ - (Some(vec![]), "ARRAY[]"), - (Some(vec!["b & c & d".to_string()]), "ARRAY['b & c & d']"), - (Some(vec!["b & c & d".to_string(), "b@* & !c".to_string()]), "ARRAY['b & c & d','b@* & !c']"), - (None, "NULL"), - ]).await; + client + .execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]) + .await + .unwrap(); + + test_type( + "ltxtquery[]", + &[ + (Some(vec![]), "ARRAY[]"), + (Some(vec!["b & c & d".to_string()]), "ARRAY['b & c & d']"), + ( + Some(vec!["b & c & d".to_string(), "b@* & !c".to_string()]), + "ARRAY['b & c & d','b@* & !c']", + ), + (None, "NULL"), + ], + ) + .await; } From 6fae6552ecc5e6755360bd33e9ede3e51b7eb566 Mon Sep 17 00:00:00 2001 From: Matt Oliver Date: Wed, 16 Mar 2022 21:20:34 -0500 Subject: [PATCH 163/420] Fix tests, replace match with matches! --- docker/sql_setup.sh | 1 + postgres-protocol/src/types/test.rs | 42 ++++---------------------- tokio-postgres/tests/test/types/mod.rs | 36 ---------------------- 3 files changed, 7 insertions(+), 72 deletions(-) diff --git a/docker/sql_setup.sh b/docker/sql_setup.sh index 422dcbda9..0315ac805 100755 --- a/docker/sql_setup.sh +++ b/docker/sql_setup.sh @@ -96,4 +96,5 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL CREATE ROLE ssl_user LOGIN; CREATE EXTENSION hstore; CREATE EXTENSION citext; + CREATE EXTENSION ltree; EOSQL diff --git a/postgres-protocol/src/types/test.rs b/postgres-protocol/src/types/test.rs index 1ce49b66f..6f1851fc2 100644 --- a/postgres-protocol/src/types/test.rs +++ b/postgres-protocol/src/types/test.rs @@ -174,12 +174,7 @@ fn ltree_str() { let mut query = vec![1u8]; query.extend_from_slice("A.B.C".as_bytes()); - let success = match ltree_from_sql(query.as_slice()) { - Ok(_) => true, - _ => false, - }; - - assert!(success) + assert!(matches!(ltree_from_sql(query.as_slice()), Ok(_))) } #[test] @@ -187,12 +182,7 @@ fn ltree_wrong_version() { let mut query = vec![2u8]; query.extend_from_slice("A.B.C".as_bytes()); - let success = match ltree_from_sql(query.as_slice()) { - Err(_) => true, - _ => false, - }; - - assert!(success) + assert!(matches!(ltree_from_sql(query.as_slice()), Err(_))) } #[test] @@ -212,12 +202,7 @@ fn lquery_str() { let mut query = vec![1u8]; query.extend_from_slice("A.B.C".as_bytes()); - let success = match lquery_from_sql(query.as_slice()) { - Ok(_) => true, - _ => false, - }; - - assert!(success) + assert!(matches!(lquery_from_sql(query.as_slice()), Ok(_))) } #[test] @@ -225,12 +210,7 @@ fn lquery_wrong_version() { let mut query = vec![2u8]; query.extend_from_slice("A.B.C".as_bytes()); - let success = match lquery_from_sql(query.as_slice()) { - Err(_) => true, - _ => false, - }; - - assert!(success) + assert!(matches!(lquery_from_sql(query.as_slice()), Err(_))) } #[test] @@ -250,12 +230,7 @@ fn ltxtquery_str() { let mut query = vec![1u8]; query.extend_from_slice("a & b*".as_bytes()); - let success = match ltree_from_sql(query.as_slice()) { - Ok(_) => true, - _ => false, - }; - - assert!(success) + assert!(matches!(ltree_from_sql(query.as_slice()), Ok(_))) } #[test] @@ -263,10 +238,5 @@ fn ltxtquery_wrong_version() { let mut query = vec![2u8]; query.extend_from_slice("a & b*".as_bytes()); - let success = match ltree_from_sql(query.as_slice()) { - Err(_) => true, - _ => false, - }; - - assert!(success) + assert!(matches!(ltree_from_sql(query.as_slice()), Err(_))) } diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index f69932e55..de700d791 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -651,12 +651,6 @@ async fn inet() { #[tokio::test] async fn ltree() { - let client = connect("user=postgres").await; - client - .execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]) - .await - .unwrap(); - test_type( "ltree", &[(Some("b.c.d".to_owned()), "'b.c.d'"), (None, "NULL")], @@ -666,12 +660,6 @@ async fn ltree() { #[tokio::test] async fn ltree_any() { - let client = connect("user=postgres").await; - client - .execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]) - .await - .unwrap(); - test_type( "ltree[]", &[ @@ -689,12 +677,6 @@ async fn ltree_any() { #[tokio::test] async fn lquery() { - let client = connect("user=postgres").await; - client - .execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]) - .await - .unwrap(); - test_type( "lquery", &[ @@ -709,12 +691,6 @@ async fn lquery() { #[tokio::test] async fn lquery_any() { - let client = connect("user=postgres").await; - client - .execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]) - .await - .unwrap(); - test_type( "lquery[]", &[ @@ -732,12 +708,6 @@ async fn lquery_any() { #[tokio::test] async fn ltxtquery() { - let client = connect("user=postgres").await; - client - .execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]) - .await - .unwrap(); - test_type( "ltxtquery", &[ @@ -751,12 +721,6 @@ async fn ltxtquery() { #[tokio::test] async fn ltxtquery_any() { - let client = connect("user=postgres").await; - client - .execute("CREATE EXTENSION IF NOT EXISTS ltree;", &[]) - .await - .unwrap(); - test_type( "ltxtquery[]", &[ From 812dfa710ab131aaa5d483bf7df660b14cbacd8e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 16 Apr 2022 09:10:09 -0400 Subject: [PATCH 164/420] Update ci.yml --- .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 520d665f8..88f4170a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: - run: docker compose up -d - uses: sfackler/actions/rustup@master with: - version: 1.53.0 + version: 1.56.0 - run: echo "::set-output name=version::$(rustc --version)" id: rust-version - uses: actions/cache@v1 From cf381ce6a2e44ca5ff13b1b2c34541d1e9af7199 Mon Sep 17 00:00:00 2001 From: Dmitry Ivanov Date: Fri, 15 Apr 2022 23:57:30 +0300 Subject: [PATCH 165/420] Hide `tokio_postgres::client::SocketConfig` behind "runtime" feature This fixes warnings reported by rust 1.60 when doing the following: ```shell $ cargo test --manifest-path tokio-postgres/Cargo.toml --no-default-features ``` --- tokio-postgres/src/client.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index dea77da94..42d507fda 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -1,5 +1,7 @@ use crate::codec::{BackendMessages, FrontendMessage}; -use crate::config::{Host, SslMode}; +#[cfg(feature = "runtime")] +use crate::config::Host; +use crate::config::SslMode; use crate::connection::{Request, RequestMessages}; use crate::copy_out::CopyOutStream; use crate::query::RowStream; @@ -25,6 +27,7 @@ use std::collections::HashMap; use std::fmt; use std::sync::Arc; use std::task::{Context, Poll}; +#[cfg(feature = "runtime")] use std::time::Duration; use tokio::io::{AsyncRead, AsyncWrite}; @@ -145,6 +148,7 @@ impl InnerClient { } } +#[cfg(feature = "runtime")] #[derive(Clone)] pub(crate) struct SocketConfig { pub host: Host, From 1d9c93d2aeff5dbb93f9d6e0d59c5f817a6162b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 20 Apr 2022 16:52:47 +0200 Subject: [PATCH 166/420] Add conversions from Uuid 1.0 --- postgres-types/Cargo.toml | 2 ++ postgres-types/src/lib.rs | 2 ++ postgres-types/src/uuid_1.rs | 25 +++++++++++++++++++++++ postgres/Cargo.toml | 1 + postgres/src/lib.rs | 1 + tokio-postgres/Cargo.toml | 2 ++ tokio-postgres/src/lib.rs | 1 + tokio-postgres/tests/test/types/mod.rs | 2 ++ tokio-postgres/tests/test/types/uuid_1.rs | 18 ++++++++++++++++ 9 files changed, 54 insertions(+) create mode 100644 postgres-types/src/uuid_1.rs create mode 100644 tokio-postgres/tests/test/types/uuid_1.rs diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 000d71ea0..e0ccb9493 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -22,6 +22,7 @@ with-geo-types-0_6 = ["geo-types-06"] with-geo-types-0_7 = ["geo-types-0_7"] with-serde_json-1 = ["serde-1", "serde_json-1"] with-uuid-0_8 = ["uuid-08"] +with-uuid-1 = ["uuid-1"] with-time-0_2 = ["time-02"] with-time-0_3 = ["time-03"] @@ -42,5 +43,6 @@ geo-types-0_7 = { version = "0.7", package = "geo-types", optional = true } serde-1 = { version = "1.0", package = "serde", optional = true } serde_json-1 = { version = "1.0", package = "serde_json", optional = true } uuid-08 = { version = "0.8", package = "uuid", optional = true } +uuid-1 = { version = "1.0", package = "uuid", optional = true } time-02 = { version = "0.2", package = "time", optional = true } time-03 = { version = "0.3", package = "time", default-features = false, optional = true } diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index d029d3948..f9c1c5ce5 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -230,6 +230,8 @@ mod time_02; mod time_03; #[cfg(feature = "with-uuid-0_8")] mod uuid_08; +#[cfg(feature = "with-uuid-1")] +mod uuid_1; // The time::{date, time} macros produce compile errors if the crate package is renamed. #[cfg(feature = "with-time-0_2")] diff --git a/postgres-types/src/uuid_1.rs b/postgres-types/src/uuid_1.rs new file mode 100644 index 000000000..d9969f60c --- /dev/null +++ b/postgres-types/src/uuid_1.rs @@ -0,0 +1,25 @@ +use bytes::BytesMut; +use postgres_protocol::types; +use std::error::Error; +use uuid_1::Uuid; + +use crate::{FromSql, IsNull, ToSql, Type}; + +impl<'a> FromSql<'a> for Uuid { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let bytes = types::uuid_from_sql(raw)?; + Ok(Uuid::from_bytes(bytes)) + } + + accepts!(UUID); +} + +impl ToSql for Uuid { + fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { + types::uuid_to_sql(*self.as_bytes(), w); + Ok(IsNull::No) + } + + accepts!(UUID); + to_sql_checked!(); +} diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index b61e42aca..12f9e98ef 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -30,6 +30,7 @@ with-geo-types-0_6 = ["tokio-postgres/with-geo-types-0_6"] with-geo-types-0_7 = ["tokio-postgres/with-geo-types-0_7"] with-serde_json-1 = ["tokio-postgres/with-serde_json-1"] with-uuid-0_8 = ["tokio-postgres/with-uuid-0_8"] +with-uuid-1 = ["tokio-postgres/with-uuid-1"] with-time-0_2 = ["tokio-postgres/with-time-0_2"] with-time-0_3 = ["tokio-postgres/with-time-0_3"] diff --git a/postgres/src/lib.rs b/postgres/src/lib.rs index a599532e4..fbe85cbde 100644 --- a/postgres/src/lib.rs +++ b/postgres/src/lib.rs @@ -61,6 +61,7 @@ //! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | +//! | `with-uuid-1` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 1.0 | no | //! | `with-time-0_2` | Enable support for the 0.2 version of the `time` crate. | [time](https://crates.io/crates/time/0.2.0) 0.2 | no | //! | `with-time-0_3` | Enable support for the 0.3 version of the `time` crate. | [time](https://crates.io/crates/time/0.3.0) 0.3 | no | #![warn(clippy::all, rust_2018_idioms, missing_docs)] diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 82e71fb1c..acb4d04e9 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -36,6 +36,7 @@ with-geo-types-0_6 = ["postgres-types/with-geo-types-0_6"] with-geo-types-0_7 = ["postgres-types/with-geo-types-0_7"] with-serde_json-1 = ["postgres-types/with-serde_json-1"] with-uuid-0_8 = ["postgres-types/with-uuid-0_8"] +with-uuid-1 = ["postgres-types/with-uuid-1"] with-time-0_2 = ["postgres-types/with-time-0_2"] with-time-0_3 = ["postgres-types/with-time-0_3"] @@ -70,5 +71,6 @@ geo-types-07 = { version = "0.7", package = "geo-types" } serde-1 = { version = "1.0", package = "serde" } serde_json-1 = { version = "1.0", package = "serde_json" } uuid-08 = { version = "0.8", package = "uuid" } +uuid-1 = { version = "1.0", package = "uuid" } time-02 = { version = "0.2", package = "time" } time-03 = { version = "0.3", package = "time", features = ["parsing"] } diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index e9516e0b3..9afb93801 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -112,6 +112,7 @@ //! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | +//! | `with-uuid-1` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 1.0 | no | //! | `with-time-0_2` | Enable support for the 0.2 version of the `time` crate. | [time](https://crates.io/crates/time/0.2.0) 0.2 | no | //! | `with-time-0_3` | Enable support for the 0.3 version of the `time` crate. | [time](https://crates.io/crates/time/0.3.0) 0.3 | no | #![doc(html_root_url = "https://docs.rs/tokio-postgres/0.7")] diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index de700d791..e3fd663a5 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -33,6 +33,8 @@ mod time_02; mod time_03; #[cfg(feature = "with-uuid-0_8")] mod uuid_08; +#[cfg(feature = "with-uuid-1")] +mod uuid_1; async fn test_type(sql_type: &str, checks: &[(T, S)]) where diff --git a/tokio-postgres/tests/test/types/uuid_1.rs b/tokio-postgres/tests/test/types/uuid_1.rs new file mode 100644 index 000000000..0eb89be8f --- /dev/null +++ b/tokio-postgres/tests/test/types/uuid_1.rs @@ -0,0 +1,18 @@ +use uuid_1::Uuid; + +use crate::types::test_type; + +#[tokio::test] +async fn test_uuid_params() { + test_type( + "UUID", + &[ + ( + Some(Uuid::parse_str("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11").unwrap()), + "'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'", + ), + (None, "NULL"), + ], + ) + .await +} From da78d4ea065d976bf4e2d711b3718055a63c9f77 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 30 Apr 2022 08:24:30 -0400 Subject: [PATCH 167/420] Release postgres-protocol v0.6.4 --- postgres-protocol/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/postgres-protocol/CHANGELOG.md b/postgres-protocol/CHANGELOG.md index 5d9cecd01..d84f29ded 100644 --- a/postgres-protocol/CHANGELOG.md +++ b/postgres-protocol/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.6.4 - 2022-04-03 + +### Added + +* Added parsing support for `ltree`, `lquery`, and `ltxtquery`. + ## v0.6.3 - 2021-12-10 ### Changed From 1d8aa0ad87873429aa2472102bca3365a73f24ce Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 30 Apr 2022 08:28:06 -0400 Subject: [PATCH 168/420] Release postgres-derive v0.4.2 --- postgres-derive/CHANGELOG.md | 6 ++++++ postgres-derive/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres-derive/CHANGELOG.md b/postgres-derive/CHANGELOG.md index 9bb3a752f..1cc55bfe8 100644 --- a/postgres-derive/CHANGELOG.md +++ b/postgres-derive/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.4.2 - 2022-04-30 + +### Added + +* Added support for transparent wrapper types. + ## v0.4.1 - 2021-11-23 ### Fixed diff --git a/postgres-derive/Cargo.toml b/postgres-derive/Cargo.toml index 1ce243a58..324400162 100644 --- a/postgres-derive/Cargo.toml +++ b/postgres-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-derive" -version = "0.4.1" +version = "0.4.2" authors = ["Steven Fackler "] license = "MIT/Apache-2.0" edition = "2018" From 695067c299e5ada849f294859be705348aecbf21 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 30 Apr 2022 08:40:30 -0400 Subject: [PATCH 169/420] Release postgres-types v0.2.3 --- postgres-types/CHANGELOG.md | 10 ++++++++++ postgres-types/Cargo.toml | 6 ++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index f8b2835eb..d2284dbd5 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## v0.2.3 - 2022-04-30 + +### Added + +* Added `ToSql` and `FromSql` implementations for `Box`. +* Added `BorrowToSql` implementations for `Box` and `Box`. +* Added support for `cidr` 0.2 via the `with-cidr-02` feature. +* Added conversions between the `LTREE`, `LQUERY` and `LTXTQUERY` types and Rust strings. +* Added support for `uuid` 1.0 via the `with-uuid-1` feature. + ## v0.2.2 - 2021-09-29 ### Added diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index e0ccb9493..d8f147022 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -30,11 +30,13 @@ with-time-0_3 = ["time-03"] bytes = "1.0" fallible-iterator = "0.2" postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" } -postgres-derive = { version = "0.4.0", optional = true, path = "../postgres-derive" } +postgres-derive = { version = "0.4.2", optional = true, path = "../postgres-derive" } array-init = { version = "2", optional = true } bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } -chrono-04 = { version = "0.4.16", package = "chrono", default-features = false, features = ["clock"], optional = true } +chrono-04 = { version = "0.4.16", package = "chrono", default-features = false, features = [ + "clock", +], optional = true } cidr-02 = { version = "0.2", package = "cidr", optional = true } eui48-04 = { version = "0.4", package = "eui48", optional = true } eui48-1 = { version = "1.0", package = "eui48", optional = true } From 17af0d5b6884839c4d7d4c3fb85347f9f1e3e633 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 30 Apr 2022 08:53:14 -0400 Subject: [PATCH 170/420] Release tokio-postgres v0.7.6 --- tokio-postgres/CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index eca196f06..b294aec69 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,5 +1,16 @@ # Change Log +## v0.7.6 - 2022-04-30 + +### Added + +* Added support for `uuid` 1.0 via the `with-uuid-1` feature. + +### Changed + +* Upgraded to `tokio-util` 0.7. +* Upgraded to `parking_lot` 0.12. + ## v0.7.5 - 2021-10-29 ### Fixed From 8785773e8e332f665471d79258dcc8f0051ebf27 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 30 Apr 2022 08:56:34 -0400 Subject: [PATCH 171/420] Release postgres v0.19.3 --- postgres/CHANGELOG.md | 6 ++++++ postgres/Cargo.toml | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index 6af8d914b..5394da803 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.19.3 - 2022-04-30 + +### Added + +* Added support for `uuid` 1.0 via the `with-uuid-1` feature. + ## v0.19.2 - 2021-09-29 ### Added diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 12f9e98ef..be59df101 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.19.2" +version = "0.19.3" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -38,7 +38,7 @@ with-time-0_3 = ["tokio-postgres/with-time-0_3"] bytes = "1.0" fallible-iterator = "0.2" futures = "0.3" -tokio-postgres = { version = "0.7.2", path = "../tokio-postgres" } +tokio-postgres = { version = "0.7.6", path = "../tokio-postgres" } tokio = { version = "1.0", features = ["rt", "time"] } log = "0.4" From a410a5fe04d487ab2ee3aadec8ceca2b12473ff3 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev <8925621+elpiel@users.noreply.github.com> Date: Tue, 21 Jun 2022 13:31:31 +0200 Subject: [PATCH 172/420] Add `array-impls` feature in docs table --- tokio-postgres/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 9afb93801..b486a9338 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -104,6 +104,7 @@ //! | Feature | Description | Extra dependencies | Default | //! | ------- | ----------- | ------------------ | ------- | //! | `runtime` | Enable convenience API for the connection process based on the `tokio` crate. | [tokio](https://crates.io/crates/tokio) 1.0 with the features `net` and `time` | yes | +//! | `array-impls` | Enables `ToSql` and `FromSql` trait impls for arrays | - | no | //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | //! | `with-eui48-0_4` | Enable support for the 0.4 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | From dd3719ddba0fda7a8e067fdf66dda78796a35de8 Mon Sep 17 00:00:00 2001 From: Lachezar Lechev Date: Wed, 22 Jun 2022 18:38:55 +0200 Subject: [PATCH 173/420] workflow - ci - bump Rust version to 1.57 Fixes #909 --- .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 88f4170a5..24c479ef9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: - run: docker compose up -d - uses: sfackler/actions/rustup@master with: - version: 1.56.0 + version: 1.57.0 - run: echo "::set-output name=version::$(rustc --version)" id: rust-version - uses: actions/cache@v1 From 1bd0d9271ebaee06ec252197fa1c58feeba2229f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Obr=C3=A9jan?= Date: Thu, 23 Jun 2022 15:38:59 +0200 Subject: [PATCH 174/420] Implement `ToSql` & `FromSql` for `Box<[T]>` --- postgres-types/src/lib.rs | 41 +++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index f9c1c5ce5..6f72a733c 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -452,10 +452,11 @@ impl WrongType { /// /// # Arrays /// -/// `FromSql` is implemented for `Vec` and `[T; N]` where `T` implements -/// `FromSql`, and corresponds to one-dimensional Postgres arrays. **Note:** -/// the impl for arrays only exist when the Cargo feature `array-impls` is -/// enabled. +/// `FromSql` is implemented for `Vec`, `Box<[T]>` and `[T; N]` where `T` +/// implements `FromSql`, and corresponds to one-dimensional Postgres arrays. +/// +/// **Note:** the impl for arrays only exist when the Cargo feature `array-impls` +/// is enabled. pub trait FromSql<'a>: Sized { /// Creates a new value of this type from a buffer of data of the specified /// Postgres `Type` in its binary format. @@ -580,6 +581,16 @@ impl<'a, T: FromSql<'a>, const N: usize> FromSql<'a> for [T; N] { } } +impl<'a, T: FromSql<'a>> FromSql<'a> for Box<[T]> { + fn from_sql(ty: &Type, raw: &'a [u8]) -> Result> { + Vec::::from_sql(ty, raw).map(Vec::into_boxed_slice) + } + + fn accepts(ty: &Type) -> bool { + Vec::::accepts(ty) + } +} + impl<'a> FromSql<'a> for Vec { fn from_sql(_: &Type, raw: &'a [u8]) -> Result, Box> { Ok(types::bytea_from_sql(raw).to_owned()) @@ -783,10 +794,12 @@ pub enum IsNull { /// /// # Arrays /// -/// `ToSql` is implemented for `Vec`, `&[T]` and `[T; N]` where `T` -/// implements `ToSql`, and corresponds to one-dimensional Postgres arrays with -/// an index offset of 1. **Note:** the impl for arrays only exist when the -/// Cargo feature `array-impls` is enabled. +/// `ToSql` is implemented for `Vec`, `&[T]`, `Box<[T]>` and `[T; N]` where +/// `T` implements `ToSql`, and corresponds to one-dimensional Postgres arrays +/// with an index offset of 1. +/// +/// **Note:** the impl for arrays only exist when the Cargo feature `array-impls` +/// is enabled. pub trait ToSql: fmt::Debug { /// Converts the value of `self` into the binary format of the specified /// Postgres `Type`, appending it to `out`. @@ -927,6 +940,18 @@ impl ToSql for Vec { to_sql_checked!(); } +impl ToSql for Box<[T]> { + fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { + <&[T] as ToSql>::to_sql(&&**self, ty, w) + } + + fn accepts(ty: &Type) -> bool { + <&[T] as ToSql>::accepts(ty) + } + + to_sql_checked!(); +} + impl ToSql for Vec { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { <&[u8] as ToSql>::to_sql(&&**self, ty, w) From 9daf8b1e5d5e230bc1c482b706ba8042b3c64420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sylwester=20R=C4=85pa=C5=82a?= Date: Wed, 29 Jun 2022 22:11:12 +0200 Subject: [PATCH 175/420] feat: support [u8; N] as BYTEA --- postgres-types/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 6f72a733c..eca2a78ca 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -915,6 +915,18 @@ impl<'a> ToSql for &'a [u8] { to_sql_checked!(); } +#[cfg(feature = "array-impls")] +impl ToSql for [u8; N] { + fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { + types::bytea_to_sql(&self[..], w); + Ok(IsNull::No) + } + + accepts!(BYTEA); + + to_sql_checked!(); +} + #[cfg(feature = "array-impls")] impl ToSql for [T; N] { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { From 6b8cb8a2be49db87322d6a75118137c0c9f51432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sylwester=20R=C4=85pa=C5=82a?= Date: Thu, 30 Jun 2022 00:13:19 +0200 Subject: [PATCH 176/420] chore: update ToSql documentation about [u8; N] --- postgres-types/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index eca2a78ca..833d8a107 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -754,7 +754,7 @@ pub enum IsNull { /// | `f64` | DOUBLE PRECISION | /// | `&str`/`String` | VARCHAR, CHAR(n), TEXT, CITEXT, NAME | /// | | LTREE, LQUERY, LTXTQUERY | -/// | `&[u8]`/`Vec` | BYTEA | +/// | `&[u8]`/`Vec`/`[u8; N]` | BYTEA | /// | `HashMap>` | HSTORE | /// | `SystemTime` | TIMESTAMP, TIMESTAMP WITH TIME ZONE | /// | `IpAddr` | INET | @@ -794,9 +794,9 @@ pub enum IsNull { /// /// # Arrays /// -/// `ToSql` is implemented for `Vec`, `&[T]`, `Box<[T]>` and `[T; N]` where -/// `T` implements `ToSql`, and corresponds to one-dimensional Postgres arrays -/// with an index offset of 1. +/// `ToSql` is implemented for `[u8; N]`, `Vec`, `&[T]`, `Box<[T]>` and `[T; N]` +/// where `T` implements `ToSql` and `N` is const usize, and corresponds to one-dimensional +/// Postgres arrays with an index offset of 1. /// /// **Note:** the impl for arrays only exist when the Cargo feature `array-impls` /// is enabled. From 7699c78037e917df070c2115dd844f2f0da805bc Mon Sep 17 00:00:00 2001 From: BratSinot Date: Mon, 4 Jul 2022 12:25:58 +0200 Subject: [PATCH 177/420] Add FromSql / ToSql for smol_str::SmolStr. --- postgres-types/Cargo.toml | 2 ++ postgres-types/src/lib.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index d8f147022..83ff718a4 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -48,3 +48,5 @@ uuid-08 = { version = "0.8", package = "uuid", optional = true } uuid-1 = { version = "1.0", package = "uuid", optional = true } time-02 = { version = "0.2", package = "time", optional = true } time-03 = { version = "0.3", package = "time", default-features = false, optional = true } + +smol_str = { version = "0.1.23", default-features = false, optional = true } diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 6f72a733c..3933f34c8 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -155,6 +155,7 @@ pub use pg_lsn::PgLsn; pub use crate::special::{Date, Timestamp}; use bytes::BytesMut; +use smol_str::SmolStr; // Number of seconds from 1970-01-01 to 2000-01-01 const TIME_SEC_CONVERSION: u64 = 946_684_800; @@ -629,6 +630,18 @@ impl<'a> FromSql<'a> for Box { } } +#[cfg(feature = "smol_str")] +impl<'a> FromSql<'a> for smol_str::SmolStr { + fn from_sql(ty: &Type, raw: &'a [u8]) -> Result> { + <&str as FromSql>::from_sql(ty, raw) + .map(SmolStr::from) + } + + fn accepts(ty: &Type) -> bool { + <&str as FromSql>::accepts(ty) + } +} + impl<'a> FromSql<'a> for &'a str { fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<&'a str, Box> { match *ty { @@ -1029,6 +1042,19 @@ impl ToSql for Box { to_sql_checked!(); } +#[cfg(feature = "smol_str")] +impl ToSql for smol_str::SmolStr { + fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { + <&str as ToSql>::to_sql(&&**self, ty, w) + } + + fn accepts(ty: &Type) -> bool { + <&str as ToSql>::accepts(ty) + } + + to_sql_checked!(); +} + macro_rules! simple_to { ($t:ty, $f:ident, $($expected:ident),+) => { impl ToSql for $t { From cff971d48cbe49ae96bec8e7df7ebe306e41f270 Mon Sep 17 00:00:00 2001 From: BratSinot Date: Tue, 5 Jul 2022 09:13:19 +0200 Subject: [PATCH 178/420] Fix suggestions. --- postgres-types/Cargo.toml | 2 +- postgres-types/src/lib.rs | 31 +++++-------------------------- postgres-types/src/smol_str_01.rs | 27 +++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 27 deletions(-) create mode 100644 postgres-types/src/smol_str_01.rs diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 83ff718a4..d84641866 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -49,4 +49,4 @@ uuid-1 = { version = "1.0", package = "uuid", optional = true } time-02 = { version = "0.2", package = "time", optional = true } time-03 = { version = "0.3", package = "time", default-features = false, optional = true } -smol_str = { version = "0.1.23", default-features = false, optional = true } +smol_str-01 = { version = "0.1.23", package = "smol_str", default-features = false, optional = true } diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 3933f34c8..c06a2fb44 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -155,7 +155,6 @@ pub use pg_lsn::PgLsn; pub use crate::special::{Date, Timestamp}; use bytes::BytesMut; -use smol_str::SmolStr; // Number of seconds from 1970-01-01 to 2000-01-01 const TIME_SEC_CONVERSION: u64 = 946_684_800; @@ -233,6 +232,8 @@ mod time_03; mod uuid_08; #[cfg(feature = "with-uuid-1")] mod uuid_1; +#[cfg(feature = "smol_str-01")] +mod smol_str_01; // The time::{date, time} macros produce compile errors if the crate package is renamed. #[cfg(feature = "with-time-0_2")] @@ -444,6 +445,9 @@ impl WrongType { /// | `eui48::MacAddress` | MACADDR | /// | `cidr::InetCidr` | CIDR | /// | `cidr::InetAddr` | INET | +/// | `smol_str::SmolStr` | VARCHAR, CHAR(n), TEXT, CITEXT, | +/// | | NAME, UNKNOWN, LTREE, LQUERY, | +/// | | LTXTQUERY | /// /// # Nullability /// @@ -630,18 +634,6 @@ impl<'a> FromSql<'a> for Box { } } -#[cfg(feature = "smol_str")] -impl<'a> FromSql<'a> for smol_str::SmolStr { - fn from_sql(ty: &Type, raw: &'a [u8]) -> Result> { - <&str as FromSql>::from_sql(ty, raw) - .map(SmolStr::from) - } - - fn accepts(ty: &Type) -> bool { - <&str as FromSql>::accepts(ty) - } -} - impl<'a> FromSql<'a> for &'a str { fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<&'a str, Box> { match *ty { @@ -1042,19 +1034,6 @@ impl ToSql for Box { to_sql_checked!(); } -#[cfg(feature = "smol_str")] -impl ToSql for smol_str::SmolStr { - fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { - <&str as ToSql>::to_sql(&&**self, ty, w) - } - - fn accepts(ty: &Type) -> bool { - <&str as ToSql>::accepts(ty) - } - - to_sql_checked!(); -} - macro_rules! simple_to { ($t:ty, $f:ident, $($expected:ident),+) => { impl ToSql for $t { diff --git a/postgres-types/src/smol_str_01.rs b/postgres-types/src/smol_str_01.rs new file mode 100644 index 000000000..a0d024ce2 --- /dev/null +++ b/postgres-types/src/smol_str_01.rs @@ -0,0 +1,27 @@ +use bytes::BytesMut; +use smol_str_01::SmolStr; +use std::error::Error; + +use crate::{FromSql, IsNull, ToSql, Type}; + +impl<'a> FromSql<'a> for SmolStr { + fn from_sql(ty: &Type, raw: &'a [u8]) -> Result> { + <&str as FromSql>::from_sql(ty, raw).map(SmolStr::from) + } + + fn accepts(ty: &Type) -> bool { + <&str as FromSql>::accepts(ty) + } +} + +impl ToSql for SmolStr { + fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { + <&str as ToSql>::to_sql(&&**self, ty, w) + } + + fn accepts(ty: &Type) -> bool { + <&str as ToSql>::accepts(ty) + } + + to_sql_checked!(); +} From db4c65e884253c700d7de363b629500f3ebc80eb Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 5 Jul 2022 07:26:32 -0400 Subject: [PATCH 179/420] clippy --- 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 833d8a107..c14350308 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -700,7 +700,7 @@ impl<'a> FromSql<'a> for SystemTime { let epoch = UNIX_EPOCH + Duration::from_secs(TIME_SEC_CONVERSION); let negative = time < 0; - let time = time.abs() as u64; + let time = time.unsigned_abs(); let secs = time / USEC_PER_SEC; let nsec = (time % USEC_PER_SEC) * NSEC_PER_USEC; From 68b1be6715bd6b8f1eef40c3b10653ce756a0a42 Mon Sep 17 00:00:00 2001 From: BratSinot Date: Tue, 5 Jul 2022 14:58:26 +0200 Subject: [PATCH 180/420] rustfmt fix --- postgres-types/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index c06a2fb44..8c32626a2 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -224,6 +224,8 @@ mod geo_types_06; mod geo_types_07; #[cfg(feature = "with-serde_json-1")] mod serde_json_1; +#[cfg(feature = "smol_str-01")] +mod smol_str_01; #[cfg(feature = "with-time-0_2")] mod time_02; #[cfg(feature = "with-time-0_3")] @@ -232,8 +234,6 @@ mod time_03; mod uuid_08; #[cfg(feature = "with-uuid-1")] mod uuid_1; -#[cfg(feature = "smol_str-01")] -mod smol_str_01; // The time::{date, time} macros produce compile errors if the crate package is renamed. #[cfg(feature = "with-time-0_2")] From e6dd655a2ada507d8095e8422fdeef20d053b98e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 18 Jul 2022 20:04:00 -0400 Subject: [PATCH 181/420] Upgrade phf --- codegen/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index 14bebccf2..bbe6b789c 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Steven Fackler "] [dependencies] -phf_codegen = "0.10" +phf_codegen = "0.11" regex = "1.0" marksman_escape = "0.1" linked-hash-map = "0.5" diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index acb4d04e9..b3b7cf825 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -50,7 +50,7 @@ log = "0.4" parking_lot = "0.12" percent-encoding = "2.0" pin-project-lite = "0.2" -phf = "0.10" +phf = "0.11" postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" } postgres-types = { version = "0.2.3", path = "../postgres-types" } socket2 = "0.4" From 8736f45fbd73ab48ab49a5401213da0007a956d6 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 18 Jul 2022 20:13:48 -0400 Subject: [PATCH 182/420] bump ci version --- .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 24c479ef9..8d17f4d6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: - run: docker compose up -d - uses: sfackler/actions/rustup@master with: - version: 1.57.0 + version: 1.62.0 - run: echo "::set-output name=version::$(rustc --version)" id: rust-version - uses: actions/cache@v1 From d7b10f2cea5edd1e625dd4b1f2e57e859008f61f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 18 Jul 2022 20:18:18 -0400 Subject: [PATCH 183/420] cleanup --- postgres-types/src/lib.rs | 15 +++------------ tokio-postgres/src/query.rs | 5 ++++- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index f4f88085e..48f6b5d43 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -836,7 +836,9 @@ pub trait ToSql: fmt::Debug { ) -> Result>; /// Specify the encode format - fn encode_format(&self) -> Format { Format::Binary } + fn encode_format(&self) -> Format { + Format::Binary + } } /// Supported Postgres message format types @@ -849,17 +851,6 @@ pub enum Format { Binary, } -/// Convert from `Format` to the Postgres integer representation of those formats -impl From for i16 { - fn from(format: Format) -> Self { - match format { - Format::Text => 0, - Format::Binary => 1, - } - } -} - - impl<'a, T> ToSql for &'a T where T: ToSql, diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index af57e2aec..965a21a48 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -156,7 +156,10 @@ where I: IntoIterator, I::IntoIter: ExactSizeIterator, { - let (param_formats, params):(Vec<_>, Vec<_>) = params.into_iter().map(|p|->(i16, P){(p.borrow_to_sql().encode_format().into(),p)}).unzip(); + let (param_formats, params): (Vec<_>, Vec<_>) = params + .into_iter() + .map(|p| { (p.borrow_to_sql().encode_format() as i16, p) }) + .unzip(); let params = params.into_iter(); assert!( From f048f39812e4024d612cc197743b9513f8238584 Mon Sep 17 00:00:00 2001 From: Harry Maclean Date: Wed, 3 Aug 2022 23:32:30 +1200 Subject: [PATCH 184/420] Derive Debug for Format It's useful to be able to inspect Format values when debugging. --- postgres-types/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 48f6b5d43..e912b378d 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -844,6 +844,7 @@ pub trait ToSql: fmt::Debug { /// Supported Postgres message format types /// /// Using Text format in a message assumes a Postgres `SERVER_ENCODING` of `UTF8` +#[derive(Debug)] pub enum Format { /// Text format (UTF-8) Text, From 0d11db69404e504ce80d41821410af20445d0141 Mon Sep 17 00:00:00 2001 From: Harry Maclean Date: Wed, 3 Aug 2022 23:33:54 +1200 Subject: [PATCH 185/420] Delegate to inner type for encode_format In the ToSql impls for &T and Option, override encode_format to delegate to the impl for T. This ensures that if T overrides this method, it also overrides it for &T and Option. --- postgres-types/src/lib.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index e912b378d..8f758e974 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -868,6 +868,10 @@ where T::accepts(ty) } + fn encode_format(&self) -> Format { + (*self).encode_format() + } + to_sql_checked!(); } @@ -887,6 +891,13 @@ impl ToSql for Option { ::accepts(ty) } + fn encode_format(&self) -> Format { + match self { + Some(ref val) => val.encode_format(), + None => Format::Binary, + } + } + to_sql_checked!(); } From 17da49912d923db0fdb8b152a09eca748806c289 Mon Sep 17 00:00:00 2001 From: Harry Maclean Date: Wed, 3 Aug 2022 23:49:19 +1200 Subject: [PATCH 186/420] Impl Clone + Copy for Format --- 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 8f758e974..463e3deec 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -844,7 +844,7 @@ pub trait ToSql: fmt::Debug { /// Supported Postgres message format types /// /// Using Text format in a message assumes a Postgres `SERVER_ENCODING` of `UTF8` -#[derive(Debug)] +#[derive(Clone, Copy, Debug)] pub enum Format { /// Text format (UTF-8) Text, From a624282bed658a53e7e09d194972a025c82dc3e0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 4 Aug 2022 13:07:13 -0400 Subject: [PATCH 187/420] rustfmt --- 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 965a21a48..dd0bd0a25 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -158,7 +158,7 @@ where { let (param_formats, params): (Vec<_>, Vec<_>) = params .into_iter() - .map(|p| { (p.borrow_to_sql().encode_format() as i16, p) }) + .map(|p| (p.borrow_to_sql().encode_format() as i16, p)) .unzip(); let params = params.into_iter(); From 65c1d146a6b3b91652f211d8c72e776164ee87a4 Mon Sep 17 00:00:00 2001 From: Basti Ortiz <39114273+Some-Dood@users.noreply.github.com> Date: Sun, 14 Aug 2022 23:31:17 +0800 Subject: [PATCH 188/420] Chore(tokio-postgres): prefer sub-crates of `futures` --- tokio-postgres/Cargo.toml | 8 +++++--- tokio-postgres/benches/bench.rs | 7 +++---- tokio-postgres/src/binary_copy.rs | 2 +- tokio-postgres/src/client.rs | 6 +++--- tokio-postgres/src/connect.rs | 2 +- tokio-postgres/src/connect_raw.rs | 4 ++-- tokio-postgres/src/connection.rs | 5 ++--- tokio-postgres/src/copy_in.rs | 5 ++--- tokio-postgres/src/copy_out.rs | 2 +- tokio-postgres/src/lib.rs | 2 +- tokio-postgres/src/prepare.rs | 2 +- tokio-postgres/src/query.rs | 2 +- tokio-postgres/src/simple_query.rs | 2 +- tokio-postgres/src/transaction.rs | 2 +- tokio-postgres/tests/test/binary_copy.rs | 2 +- tokio-postgres/tests/test/main.rs | 4 ++-- tokio-postgres/tests/test/runtime.rs | 2 +- 17 files changed, 29 insertions(+), 30 deletions(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index b3b7cf825..ecd6c7faa 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -45,7 +45,8 @@ async-trait = "0.1" bytes = "1.0" byteorder = "1.0" fallible-iterator = "0.2" -futures = "0.3" +futures-channel = { version = "0.3", features = ["sink"] } +futures-util = { version = "0.3", features = ["sink"] } log = "0.4" parking_lot = "0.12" percent-encoding = "2.0" @@ -58,9 +59,10 @@ tokio = { version = "1.0", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } [dev-dependencies] -tokio = { version = "1.0", features = ["full"] } -env_logger = "0.9" +futures-executor = "0.3" criterion = "0.3" +env_logger = "0.9" +tokio = { version = "1.0", features = ["macros", "rt"] } bit-vec-06 = { version = "0.6", package = "bit-vec" } chrono-04 = { version = "0.4", package = "chrono", default-features = false } diff --git a/tokio-postgres/benches/bench.rs b/tokio-postgres/benches/bench.rs index fececa2b5..a8f9b5f1a 100644 --- a/tokio-postgres/benches/bench.rs +++ b/tokio-postgres/benches/bench.rs @@ -1,6 +1,5 @@ use criterion::{criterion_group, criterion_main, Criterion}; -use futures::channel::oneshot; -use futures::executor; +use futures_channel::oneshot; use std::sync::Arc; use std::time::Instant; use tokio::runtime::Runtime; @@ -32,7 +31,7 @@ fn query_prepared(c: &mut Criterion) { let (client, runtime) = setup(); let statement = runtime.block_on(client.prepare("SELECT $1::INT8")).unwrap(); c.bench_function("executor_block_on", move |b| { - b.iter(|| executor::block_on(client.query(&statement, &[&1i64])).unwrap()) + b.iter(|| futures_executor::block_on(client.query(&statement, &[&1i64])).unwrap()) }); let (client, runtime) = setup(); @@ -50,7 +49,7 @@ fn query_prepared(c: &mut Criterion) { } tx.send(start.elapsed()).unwrap(); }); - executor::block_on(rx).unwrap() + futures_executor::block_on(rx).unwrap() }) }); } diff --git a/tokio-postgres/src/binary_copy.rs b/tokio-postgres/src/binary_copy.rs index 3b1e13cd7..dab141663 100644 --- a/tokio-postgres/src/binary_copy.rs +++ b/tokio-postgres/src/binary_copy.rs @@ -4,7 +4,7 @@ use crate::types::{FromSql, IsNull, ToSql, Type, WrongType}; use crate::{slice_iter, CopyInSink, CopyOutStream, Error}; use byteorder::{BigEndian, ByteOrder}; use bytes::{Buf, BufMut, Bytes, BytesMut}; -use futures::{ready, SinkExt, Stream}; +use futures_util::{ready, SinkExt, Stream}; use pin_project_lite::pin_project; use postgres_types::BorrowToSql; use std::convert::TryFrom; diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 42d507fda..8444ff56a 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -18,8 +18,8 @@ use crate::{ }; use bytes::{Buf, BytesMut}; use fallible_iterator::FallibleIterator; -use futures::channel::mpsc; -use futures::{future, pin_mut, ready, StreamExt, TryStreamExt}; +use futures_channel::mpsc; +use futures_util::{future, pin_mut, ready, StreamExt, TryStreamExt}; use parking_lot::Mutex; use postgres_protocol::message::{backend::Message, frontend}; use postgres_types::BorrowToSql; @@ -341,7 +341,7 @@ impl Client { /// ```no_run /// # async fn async_main(client: &tokio_postgres::Client) -> Result<(), tokio_postgres::Error> { /// use tokio_postgres::types::ToSql; - /// use futures::{pin_mut, TryStreamExt}; + /// use futures_util::{pin_mut, TryStreamExt}; /// /// let params: Vec = vec![ /// "first param".into(), diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index f529ddbbb..4336f90be 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -4,7 +4,7 @@ use crate::connect_raw::connect_raw; use crate::connect_socket::connect_socket; use crate::tls::{MakeTlsConnect, TlsConnect}; use crate::{Client, Config, Connection, Error, SimpleQueryMessage, Socket}; -use futures::{future, pin_mut, Future, FutureExt, Stream}; +use futures_util::{future, pin_mut, Future, FutureExt, Stream}; use std::io; use std::task::Poll; diff --git a/tokio-postgres/src/connect_raw.rs b/tokio-postgres/src/connect_raw.rs index 3c6658481..d97636221 100644 --- a/tokio-postgres/src/connect_raw.rs +++ b/tokio-postgres/src/connect_raw.rs @@ -6,8 +6,8 @@ use crate::tls::{TlsConnect, TlsStream}; use crate::{Client, Connection, Error}; use bytes::BytesMut; use fallible_iterator::FallibleIterator; -use futures::channel::mpsc; -use futures::{ready, Sink, SinkExt, Stream, TryStreamExt}; +use futures_channel::mpsc; +use futures_util::{ready, Sink, SinkExt, Stream, TryStreamExt}; use postgres_protocol::authentication; use postgres_protocol::authentication::sasl; use postgres_protocol::authentication::sasl::ScramSha256; diff --git a/tokio-postgres/src/connection.rs b/tokio-postgres/src/connection.rs index b6805f76c..30be4e834 100644 --- a/tokio-postgres/src/connection.rs +++ b/tokio-postgres/src/connection.rs @@ -5,9 +5,8 @@ use crate::maybe_tls_stream::MaybeTlsStream; use crate::{AsyncMessage, Error, Notification}; use bytes::BytesMut; use fallible_iterator::FallibleIterator; -use futures::channel::mpsc; -use futures::stream::FusedStream; -use futures::{ready, Sink, Stream, StreamExt}; +use futures_channel::mpsc; +use futures_util::{ready, stream::FusedStream, Sink, Stream, StreamExt}; use log::{info, trace}; use postgres_protocol::message::backend::Message; use postgres_protocol::message::frontend; diff --git a/tokio-postgres/src/copy_in.rs b/tokio-postgres/src/copy_in.rs index bc90e5277..de1da933b 100644 --- a/tokio-postgres/src/copy_in.rs +++ b/tokio-postgres/src/copy_in.rs @@ -3,9 +3,8 @@ use crate::codec::FrontendMessage; use crate::connection::RequestMessages; use crate::{query, slice_iter, Error, Statement}; use bytes::{Buf, BufMut, BytesMut}; -use futures::channel::mpsc; -use futures::future; -use futures::{ready, Sink, SinkExt, Stream, StreamExt}; +use futures_channel::mpsc; +use futures_util::{future, ready, Sink, SinkExt, Stream, StreamExt}; use log::debug; use pin_project_lite::pin_project; use postgres_protocol::message::backend::Message; diff --git a/tokio-postgres/src/copy_out.rs b/tokio-postgres/src/copy_out.rs index 52691b963..1e6949252 100644 --- a/tokio-postgres/src/copy_out.rs +++ b/tokio-postgres/src/copy_out.rs @@ -3,7 +3,7 @@ use crate::codec::FrontendMessage; use crate::connection::RequestMessages; use crate::{query, slice_iter, Error, Statement}; use bytes::Bytes; -use futures::{ready, Stream}; +use futures_util::{ready, Stream}; use log::debug; use pin_project_lite::pin_project; use postgres_protocol::message::backend::Message; diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index b486a9338..4056819fd 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -69,7 +69,7 @@ //! combinator): //! //! ```rust -//! use futures::future; +//! use futures_util::future; //! use std::future::Future; //! use tokio_postgres::{Client, Error, Statement}; //! diff --git a/tokio-postgres/src/prepare.rs b/tokio-postgres/src/prepare.rs index 7a6163415..e3f09a7c2 100644 --- a/tokio-postgres/src/prepare.rs +++ b/tokio-postgres/src/prepare.rs @@ -7,7 +7,7 @@ use crate::{query, slice_iter}; use crate::{Column, Error, Statement}; use bytes::Bytes; use fallible_iterator::FallibleIterator; -use futures::{pin_mut, TryStreamExt}; +use futures_util::{pin_mut, TryStreamExt}; use log::debug; use postgres_protocol::message::backend::Message; use postgres_protocol::message::frontend; diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index dd0bd0a25..f1593dbc4 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -4,7 +4,7 @@ use crate::connection::RequestMessages; use crate::types::{BorrowToSql, IsNull}; use crate::{Error, Portal, Row, Statement}; use bytes::{Bytes, BytesMut}; -use futures::{ready, Stream}; +use futures_util::{ready, Stream}; use log::{debug, log_enabled, Level}; use pin_project_lite::pin_project; use postgres_protocol::message::backend::Message; diff --git a/tokio-postgres/src/simple_query.rs b/tokio-postgres/src/simple_query.rs index ade2e1d6d..19cb10236 100644 --- a/tokio-postgres/src/simple_query.rs +++ b/tokio-postgres/src/simple_query.rs @@ -4,7 +4,7 @@ use crate::connection::RequestMessages; use crate::{Error, SimpleQueryMessage, SimpleQueryRow}; use bytes::Bytes; use fallible_iterator::FallibleIterator; -use futures::{ready, Stream}; +use futures_util::{ready, Stream}; use log::debug; use pin_project_lite::pin_project; use postgres_protocol::message::backend::Message; diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index b72b119bf..96a324652 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -13,7 +13,7 @@ use crate::{ SimpleQueryMessage, Statement, ToStatement, }; use bytes::Buf; -use futures::TryStreamExt; +use futures_util::TryStreamExt; use postgres_protocol::message::frontend; use tokio::io::{AsyncRead, AsyncWrite}; diff --git a/tokio-postgres/tests/test/binary_copy.rs b/tokio-postgres/tests/test/binary_copy.rs index ab69742dc..94b96ab85 100644 --- a/tokio-postgres/tests/test/binary_copy.rs +++ b/tokio-postgres/tests/test/binary_copy.rs @@ -1,5 +1,5 @@ use crate::connect; -use futures::{pin_mut, TryStreamExt}; +use futures_util::{pin_mut, TryStreamExt}; use tokio_postgres::binary_copy::{BinaryCopyInWriter, BinaryCopyOutStream}; use tokio_postgres::types::Type; diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index dcfbc5308..0ab4a7bab 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -1,8 +1,8 @@ #![warn(rust_2018_idioms)] use bytes::{Bytes, BytesMut}; -use futures::channel::mpsc; -use futures::{ +use futures_channel::mpsc; +use futures_util::{ future, join, pin_mut, stream, try_join, Future, FutureExt, SinkExt, StreamExt, TryStreamExt, }; use pin_project_lite::pin_project; diff --git a/tokio-postgres/tests/test/runtime.rs b/tokio-postgres/tests/test/runtime.rs index b088d6c98..67b4ead8a 100644 --- a/tokio-postgres/tests/test/runtime.rs +++ b/tokio-postgres/tests/test/runtime.rs @@ -1,4 +1,4 @@ -use futures::{join, FutureExt}; +use futures_util::{join, FutureExt}; use std::time::Duration; use tokio::time; use tokio_postgres::error::SqlState; From aeb8fe0df011f289faedb773ce8acab69809ff14 Mon Sep 17 00:00:00 2001 From: Basti Ortiz <39114273+Some-Dood@users.noreply.github.com> Date: Sun, 14 Aug 2022 23:43:12 +0800 Subject: [PATCH 189/420] Chore: remove unused `futures` crate for `openssl` and `native-tls` --- postgres-native-tls/Cargo.toml | 4 ++-- postgres-native-tls/src/test.rs | 2 +- postgres-openssl/Cargo.toml | 4 ++-- postgres-openssl/src/test.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index 8180cd012..1f2f6385d 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -16,12 +16,12 @@ default = ["runtime"] runtime = ["tokio-postgres/runtime"] [dependencies] -futures = "0.3" native-tls = "0.2" tokio = "1.0" tokio-native-tls = "0.3" tokio-postgres = { version = "0.7.0", path = "../tokio-postgres", default-features = false } [dev-dependencies] -tokio = { version = "1.0", features = ["full"] } +futures-util = "0.3" +tokio = { version = "1.0", features = ["macros", "net", "rt"] } postgres = { version = "0.19.0", path = "../postgres" } diff --git a/postgres-native-tls/src/test.rs b/postgres-native-tls/src/test.rs index 7a50bc672..25cc6fdbd 100644 --- a/postgres-native-tls/src/test.rs +++ b/postgres-native-tls/src/test.rs @@ -1,4 +1,4 @@ -use futures::FutureExt; +use futures_util::FutureExt; use native_tls::{self, Certificate}; use tokio::net::TcpStream; use tokio_postgres::tls::TlsConnect; diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index 5738e74d2..8671308af 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -16,12 +16,12 @@ default = ["runtime"] runtime = ["tokio-postgres/runtime"] [dependencies] -futures = "0.3" openssl = "0.10" tokio = "1.0" tokio-openssl = "0.6" tokio-postgres = { version = "0.7.0", path = "../tokio-postgres", default-features = false } [dev-dependencies] -tokio = { version = "1.0", features = ["full"] } +futures-util = "0.3" +tokio = { version = "1.0", features = ["macros", "net", "rt"] } postgres = { version = "0.19.0", path = "../postgres" } diff --git a/postgres-openssl/src/test.rs b/postgres-openssl/src/test.rs index 15ed90ad5..b361ee446 100644 --- a/postgres-openssl/src/test.rs +++ b/postgres-openssl/src/test.rs @@ -1,4 +1,4 @@ -use futures::FutureExt; +use futures_util::FutureExt; use openssl::ssl::{SslConnector, SslMethod}; use tokio::net::TcpStream; use tokio_postgres::tls::TlsConnect; From 8abc3eaa658c062bdf96866cd48eef22ab11a8b9 Mon Sep 17 00:00:00 2001 From: Basti Ortiz <39114273+Some-Dood@users.noreply.github.com> Date: Sun, 14 Aug 2022 23:49:40 +0800 Subject: [PATCH 190/420] Chore(postgres): prefer sub-crates of `futures` --- postgres/Cargo.toml | 3 ++- postgres/src/binary_copy.rs | 2 +- postgres/src/connection.rs | 3 +-- postgres/src/copy_in_writer.rs | 2 +- postgres/src/copy_out_reader.rs | 2 +- postgres/src/notifications.rs | 2 +- postgres/src/row_iter.rs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index be59df101..15b1b32eb 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -37,7 +37,7 @@ with-time-0_3 = ["tokio-postgres/with-time-0_3"] [dependencies] bytes = "1.0" fallible-iterator = "0.2" -futures = "0.3" +futures-util = { version = "0.3", features = ["sink"] } tokio-postgres = { version = "0.7.6", path = "../tokio-postgres" } tokio = { version = "1.0", features = ["rt", "time"] } @@ -45,3 +45,4 @@ log = "0.4" [dev-dependencies] criterion = "0.3" +tokio = { version = "1.0", features = ["rt-multi-thread"] } diff --git a/postgres/src/binary_copy.rs b/postgres/src/binary_copy.rs index 98ae666b7..1c4eb7d3b 100644 --- a/postgres/src/binary_copy.rs +++ b/postgres/src/binary_copy.rs @@ -4,7 +4,7 @@ use crate::connection::ConnectionRef; use crate::types::{BorrowToSql, ToSql, Type}; use crate::{CopyInWriter, CopyOutReader, Error}; use fallible_iterator::FallibleIterator; -use futures::StreamExt; +use futures_util::StreamExt; use std::pin::Pin; #[doc(inline)] pub use tokio_postgres::binary_copy::BinaryCopyOutRow; diff --git a/postgres/src/connection.rs b/postgres/src/connection.rs index 453eef3a6..b91c16555 100644 --- a/postgres/src/connection.rs +++ b/postgres/src/connection.rs @@ -1,6 +1,5 @@ use crate::{Error, Notification}; -use futures::future; -use futures::{pin_mut, Stream}; +use futures_util::{future, pin_mut, Stream}; use std::collections::VecDeque; use std::future::Future; use std::ops::{Deref, DerefMut}; diff --git a/postgres/src/copy_in_writer.rs b/postgres/src/copy_in_writer.rs index c996ed857..7de663637 100644 --- a/postgres/src/copy_in_writer.rs +++ b/postgres/src/copy_in_writer.rs @@ -1,7 +1,7 @@ use crate::connection::ConnectionRef; use crate::lazy_pin::LazyPin; use bytes::{Bytes, BytesMut}; -use futures::SinkExt; +use futures_util::SinkExt; use std::io; use std::io::Write; use tokio_postgres::{CopyInSink, Error}; diff --git a/postgres/src/copy_out_reader.rs b/postgres/src/copy_out_reader.rs index e8b478d49..828b71873 100644 --- a/postgres/src/copy_out_reader.rs +++ b/postgres/src/copy_out_reader.rs @@ -1,7 +1,7 @@ use crate::connection::ConnectionRef; use crate::lazy_pin::LazyPin; use bytes::{Buf, Bytes}; -use futures::StreamExt; +use futures_util::StreamExt; use std::io::{self, BufRead, Read}; use tokio_postgres::CopyOutStream; diff --git a/postgres/src/notifications.rs b/postgres/src/notifications.rs index ea44c31f8..c31d4f631 100644 --- a/postgres/src/notifications.rs +++ b/postgres/src/notifications.rs @@ -3,7 +3,7 @@ use crate::connection::ConnectionRef; use crate::{Error, Notification}; use fallible_iterator::FallibleIterator; -use futures::{ready, FutureExt}; +use futures_util::{ready, FutureExt}; use std::pin::Pin; use std::task::Poll; use std::time::Duration; diff --git a/postgres/src/row_iter.rs b/postgres/src/row_iter.rs index 3cd41b900..772e9893c 100644 --- a/postgres/src/row_iter.rs +++ b/postgres/src/row_iter.rs @@ -1,6 +1,6 @@ use crate::connection::ConnectionRef; use fallible_iterator::FallibleIterator; -use futures::StreamExt; +use futures_util::StreamExt; use std::pin::Pin; use tokio_postgres::{Error, Row, RowStream}; From a0f028a008cf112ddafd808efbf998a0f2cbbdc1 Mon Sep 17 00:00:00 2001 From: Basti Ortiz <39114273+Some-Dood@users.noreply.github.com> Date: Mon, 15 Aug 2022 00:01:12 +0800 Subject: [PATCH 191/420] Fix(tokio-postgres): declare dependency on `net` feature --- tokio-postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index ecd6c7faa..57af56765 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -62,7 +62,7 @@ tokio-util = { version = "0.7", features = ["codec"] } futures-executor = "0.3" criterion = "0.3" env_logger = "0.9" -tokio = { version = "1.0", features = ["macros", "rt"] } +tokio = { version = "1.0", features = ["macros", "net", "rt", "rt-multi-thread", "time"] } bit-vec-06 = { version = "0.6", package = "bit-vec" } chrono-04 = { version = "0.4", package = "chrono", default-features = false } From 5f3e7aecad05f49a6501e53d10f0cef06f5c72cd Mon Sep 17 00:00:00 2001 From: Basti Ortiz <39114273+Some-Dood@users.noreply.github.com> Date: Mon, 15 Aug 2022 00:12:18 +0800 Subject: [PATCH 192/420] Fix: address Clippy warnings --- postgres-openssl/src/lib.rs | 4 +++- postgres-types/src/special.rs | 4 ++-- tokio-postgres/src/config.rs | 14 +++++++------- tokio-postgres/src/connect.rs | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/postgres-openssl/src/lib.rs b/postgres-openssl/src/lib.rs index 49fc2807c..9fc50b894 100644 --- a/postgres-openssl/src/lib.rs +++ b/postgres-openssl/src/lib.rs @@ -73,6 +73,8 @@ use tokio_postgres::tls::{ChannelBinding, TlsConnect}; #[cfg(test)] mod test; +type ConfigCallback = dyn Fn(&mut ConnectConfiguration, &str) -> Result<(), ErrorStack> + Sync + Send; + /// A `MakeTlsConnect` implementation using the `openssl` crate. /// /// Requires the `runtime` Cargo feature (enabled by default). @@ -80,7 +82,7 @@ mod test; #[derive(Clone)] pub struct MakeTlsConnector { connector: SslConnector, - config: Arc Result<(), ErrorStack> + Sync + Send>, + config: Arc, } #[cfg(feature = "runtime")] diff --git a/postgres-types/src/special.rs b/postgres-types/src/special.rs index 8579885ef..1a865287e 100644 --- a/postgres-types/src/special.rs +++ b/postgres-types/src/special.rs @@ -6,7 +6,7 @@ use std::{i32, i64}; use crate::{FromSql, IsNull, ToSql, Type}; /// A wrapper that can be used to represent infinity with `Type::Date` types. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Date { /// Represents `infinity`, a date that is later than all other dates. PosInfinity, @@ -55,7 +55,7 @@ impl ToSql for Date { /// A wrapper that can be used to represent infinity with `Type::Timestamp` and `Type::Timestamptz` /// types. -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Timestamp { /// Represents `infinity`, a timestamp that is later than all other timestamps. PosInfinity, diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index c026cca4f..2c29d629c 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -23,7 +23,7 @@ use std::{error, fmt, iter, mem}; use tokio::io::{AsyncRead, AsyncWrite}; /// Properties required of a session. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[non_exhaustive] pub enum TargetSessionAttrs { /// No special properties are required. @@ -33,7 +33,7 @@ pub enum TargetSessionAttrs { } /// TLS configuration. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[non_exhaustive] pub enum SslMode { /// Do not use TLS. @@ -45,7 +45,7 @@ pub enum SslMode { } /// Channel binding configuration. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[non_exhaustive] pub enum ChannelBinding { /// Do not use channel binding. @@ -57,7 +57,7 @@ pub enum ChannelBinding { } /// A host specification. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Host { /// A TCP hostname. Tcp(String), @@ -144,7 +144,7 @@ pub enum Host { /// ```not_rust /// postgresql:///mydb?user=user&host=/var/lib/postgresql /// ``` -#[derive(PartialEq, Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct Config { pub(crate) user: Option, pub(crate) password: Option>, @@ -452,7 +452,7 @@ impl Config { } } "target_session_attrs" => { - let target_session_attrs = match &*value { + let target_session_attrs = match value { "any" => TargetSessionAttrs::Any, "read-write" => TargetSessionAttrs::ReadWrite, _ => { @@ -900,7 +900,7 @@ impl<'a> UrlParser<'a> { #[cfg(unix)] fn host_param(&mut self, s: &str) -> Result<(), Error> { let decoded = Cow::from(percent_encoding::percent_decode(s.as_bytes())); - if decoded.get(0) == Some(&b'/') { + if decoded.first() == Some(&b'/') { self.config.host_path(OsStr::from_bytes(&decoded)); } else { let decoded = str::from_utf8(&decoded).map_err(|e| Error::config_parse(Box::new(e)))?; diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 4336f90be..88faafe6b 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -28,7 +28,7 @@ where let port = config .port .get(i) - .or_else(|| config.port.get(0)) + .or_else(|| config.port.first()) .copied() .unwrap_or(5432); From 44eac98271cc6c47215fb44d995695a986dfad70 Mon Sep 17 00:00:00 2001 From: Basti Ortiz <39114273+Some-Dood@users.noreply.github.com> Date: Mon, 15 Aug 2022 00:14:55 +0800 Subject: [PATCH 193/420] Fix: run `cargo fmt` --- postgres-openssl/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/postgres-openssl/src/lib.rs b/postgres-openssl/src/lib.rs index 9fc50b894..837663fe7 100644 --- a/postgres-openssl/src/lib.rs +++ b/postgres-openssl/src/lib.rs @@ -73,7 +73,8 @@ use tokio_postgres::tls::{ChannelBinding, TlsConnect}; #[cfg(test)] mod test; -type ConfigCallback = dyn Fn(&mut ConnectConfiguration, &str) -> Result<(), ErrorStack> + Sync + Send; +type ConfigCallback = + dyn Fn(&mut ConnectConfiguration, &str) -> Result<(), ErrorStack> + Sync + Send; /// A `MakeTlsConnect` implementation using the `openssl` crate. /// From 569689deaa8277e5ae8f6f28ea0b733c43a4d141 Mon Sep 17 00:00:00 2001 From: Alex Pearson Date: Mon, 15 Aug 2022 12:21:20 -0400 Subject: [PATCH 194/420] encode format with types --- postgres-types/src/lib.rs | 10 +++++----- tokio-postgres/src/query.rs | 10 ++++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 463e3deec..5c5a0d023 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -836,7 +836,7 @@ pub trait ToSql: fmt::Debug { ) -> Result>; /// Specify the encode format - fn encode_format(&self) -> Format { + fn encode_format(&self, _ty: &Type) -> Format { Format::Binary } } @@ -868,8 +868,8 @@ where T::accepts(ty) } - fn encode_format(&self) -> Format { - (*self).encode_format() + fn encode_format(&self, ty: &Type) -> Format { + (*self).encode_format(ty) } to_sql_checked!(); @@ -891,9 +891,9 @@ impl ToSql for Option { ::accepts(ty) } - fn encode_format(&self) -> Format { + fn encode_format(&self, ty: &Type) -> Format { match self { - Some(ref val) => val.encode_format(), + Some(ref val) => val.encode_format(ty), None => Format::Binary, } } diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index f1593dbc4..5f8cbf7c0 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -156,16 +156,18 @@ where I: IntoIterator, I::IntoIter: ExactSizeIterator, { + let param_types = statement.params(); let (param_formats, params): (Vec<_>, Vec<_>) = params .into_iter() - .map(|p| (p.borrow_to_sql().encode_format() as i16, p)) + .zip(param_types.iter()) + .map(|(p, ty)| (p.borrow_to_sql().encode_format(ty) as i16, p)) .unzip(); let params = params.into_iter(); assert!( - statement.params().len() == params.len(), + param_types.len() == params.len(), "expected {} parameters but got {}", - statement.params().len(), + param_types.len(), params.len() ); @@ -174,7 +176,7 @@ where portal, statement.name(), param_formats, - params.zip(statement.params()).enumerate(), + params.zip(param_types).enumerate(), |(idx, (param, ty)), buf| match param.borrow_to_sql().to_sql_checked(ty, buf) { Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No), Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes), From 8158eed052f653ffecf6921066ed3b7e5860ee5d Mon Sep 17 00:00:00 2001 From: Alex Pearson Date: Mon, 15 Aug 2022 20:54:11 -0400 Subject: [PATCH 195/420] Move parameter count assertion above format encoding derivation --- tokio-postgres/src/query.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index 5f8cbf7c0..71db8769a 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -157,11 +157,6 @@ where I::IntoIter: ExactSizeIterator, { let param_types = statement.params(); - let (param_formats, params): (Vec<_>, Vec<_>) = params - .into_iter() - .zip(param_types.iter()) - .map(|(p, ty)| (p.borrow_to_sql().encode_format(ty) as i16, p)) - .unzip(); let params = params.into_iter(); assert!( @@ -171,6 +166,13 @@ where params.len() ); + let (param_formats, params): (Vec<_>, Vec<_>) = params + .zip(param_types.iter()) + .map(|(p, ty)| (p.borrow_to_sql().encode_format(ty) as i16, p)) + .unzip(); + + let params = params.into_iter(); + let mut error_idx = 0; let r = frontend::bind( portal, From d6a6e9db830bc22a97e4ec2f1b0cde3c3a45e6c0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 20 Aug 2022 15:18:19 -0400 Subject: [PATCH 196/420] Fix smol_str feature --- postgres-types/Cargo.toml | 4 ++-- postgres-types/src/lib.rs | 2 +- postgres/Cargo.toml | 1 + tokio-postgres/Cargo.toml | 10 +++++++++- tokio-postgres/tests/test/types/mod.rs | 2 ++ tokio-postgres/tests/test/types/smol_str_01.rs | 18 ++++++++++++++++++ 6 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 tokio-postgres/tests/test/types/smol_str_01.rs diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index d84641866..70f1ed54a 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-types" -version = "0.2.3" +version = "0.2.4" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -21,6 +21,7 @@ with-eui48-1 = ["eui48-1"] with-geo-types-0_6 = ["geo-types-06"] with-geo-types-0_7 = ["geo-types-0_7"] with-serde_json-1 = ["serde-1", "serde_json-1"] +with-smol_str-01 = ["smol_str-01"] with-uuid-0_8 = ["uuid-08"] with-uuid-1 = ["uuid-1"] with-time-0_2 = ["time-02"] @@ -48,5 +49,4 @@ uuid-08 = { version = "0.8", package = "uuid", optional = true } uuid-1 = { version = "1.0", package = "uuid", optional = true } time-02 = { version = "0.2", package = "time", optional = true } time-03 = { version = "0.3", package = "time", default-features = false, optional = true } - smol_str-01 = { version = "0.1.23", package = "smol_str", default-features = false, optional = true } diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 5c5a0d023..f5d841cd1 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -224,7 +224,7 @@ mod geo_types_06; mod geo_types_07; #[cfg(feature = "with-serde_json-1")] mod serde_json_1; -#[cfg(feature = "smol_str-01")] +#[cfg(feature = "with-smol_str-01")] mod smol_str_01; #[cfg(feature = "with-time-0_2")] mod time_02; diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 15b1b32eb..b7f0e2ca5 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -29,6 +29,7 @@ with-eui48-1 = ["tokio-postgres/with-eui48-1"] with-geo-types-0_6 = ["tokio-postgres/with-geo-types-0_6"] with-geo-types-0_7 = ["tokio-postgres/with-geo-types-0_7"] with-serde_json-1 = ["tokio-postgres/with-serde_json-1"] +with-smol_str-01 = ["tokio-postgres/with-smol_str-01"] with-uuid-0_8 = ["tokio-postgres/with-uuid-0_8"] with-uuid-1 = ["tokio-postgres/with-uuid-1"] with-time-0_2 = ["tokio-postgres/with-time-0_2"] diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 57af56765..b2190c9af 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -35,6 +35,7 @@ with-eui48-1 = ["postgres-types/with-eui48-1"] with-geo-types-0_6 = ["postgres-types/with-geo-types-0_6"] with-geo-types-0_7 = ["postgres-types/with-geo-types-0_7"] with-serde_json-1 = ["postgres-types/with-serde_json-1"] +with-smol_str-01 = ["postgres-types/with-smol_str-01"] with-uuid-0_8 = ["postgres-types/with-uuid-0_8"] with-uuid-1 = ["postgres-types/with-uuid-1"] with-time-0_2 = ["postgres-types/with-time-0_2"] @@ -62,7 +63,13 @@ tokio-util = { version = "0.7", features = ["codec"] } futures-executor = "0.3" criterion = "0.3" env_logger = "0.9" -tokio = { version = "1.0", features = ["macros", "net", "rt", "rt-multi-thread", "time"] } +tokio = { version = "1.0", features = [ + "macros", + "net", + "rt", + "rt-multi-thread", + "time", +] } bit-vec-06 = { version = "0.6", package = "bit-vec" } chrono-04 = { version = "0.4", package = "chrono", default-features = false } @@ -72,6 +79,7 @@ geo-types-06 = { version = "0.6", package = "geo-types" } geo-types-07 = { version = "0.7", package = "geo-types" } serde-1 = { version = "1.0", package = "serde" } serde_json-1 = { version = "1.0", package = "serde_json" } +smol_str-01 = { version = "0.1", package = "smol_str" } uuid-08 = { version = "0.8", package = "uuid" } uuid-1 = { version = "1.0", package = "uuid" } time-02 = { version = "0.2", package = "time" } diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index e3fd663a5..452d149fe 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -27,6 +27,8 @@ mod geo_types_06; mod geo_types_07; #[cfg(feature = "with-serde_json-1")] mod serde_json_1; +#[cfg(feature = "with-smol_str-01")] +mod smol_str_01; #[cfg(feature = "with-time-0_2")] mod time_02; #[cfg(feature = "with-time-0_3")] diff --git a/tokio-postgres/tests/test/types/smol_str_01.rs b/tokio-postgres/tests/test/types/smol_str_01.rs new file mode 100644 index 000000000..843d486b9 --- /dev/null +++ b/tokio-postgres/tests/test/types/smol_str_01.rs @@ -0,0 +1,18 @@ +use smol_str_01::SmolStr; + +use crate::types::test_type; + +#[tokio::test] +async fn test_smol_str() { + test_type( + "VARCHAR", + &[ + (Some(SmolStr::new("hello world")), "'hello world'"), + ( + Some(SmolStr::new("イロハニホヘト チリヌルヲ")), + "'イロハニホヘト チリヌルヲ'", + ), + (None, "NULL"), + ] + ).await; +} From 34efb053ec41b97d687395a94081651a546c4a5c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 20 Aug 2022 15:19:17 -0400 Subject: [PATCH 197/420] rustfmt --- tokio-postgres/tests/test/types/smol_str_01.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/tests/test/types/smol_str_01.rs b/tokio-postgres/tests/test/types/smol_str_01.rs index 843d486b9..105a2c957 100644 --- a/tokio-postgres/tests/test/types/smol_str_01.rs +++ b/tokio-postgres/tests/test/types/smol_str_01.rs @@ -13,6 +13,7 @@ async fn test_smol_str() { "'イロハニホヘト チリヌルヲ'", ), (None, "NULL"), - ] - ).await; + ], + ) + .await; } From 5b95068ee6e644c5234d3663d2d6156baa1747ae Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 20 Aug 2022 15:28:42 -0400 Subject: [PATCH 198/420] Release postgres-types v0.2.4 --- postgres-types/CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index d2284dbd5..0e2167e5f 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -1,5 +1,14 @@ # Change Log +## v0.2.4 - 2022-08-20 + +## Added + +* Added `ToSql` and `FromSql` implementations for `Box<[T]>`. +* Added `ToSql` and `FromSql` implementations for `[u8; N]` via the `array-impls` feature. +* Added support for `smol_str` 0.1 via the `with-smol_str-01` feature. +* Added `ToSql::encode_format` to support text encodings of parameters. + ## v0.2.3 - 2022-04-30 ### Added From 8e4484c005499883882e5f9584988e0eceac4eca Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 21 Aug 2022 15:34:36 -0400 Subject: [PATCH 199/420] Release tokio-postgres v0.7.7 --- tokio-postgres/CHANGELOG.md | 8 ++++++++ tokio-postgres/Cargo.toml | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index b294aec69..91e78b780 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## v0.7.7 - 2022-08-21 + +## Added + +* Added `ToSql` and `FromSql` implementations for `[u8; N]` via the `array-impls` feature. +* Added support for `smol_str` 0.1 via the `with-smol_str-01` feature. +* Added `ToSql::encode_format` to support text encodings of parameters. + ## v0.7.6 - 2022-04-30 ### Added diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index b2190c9af..1a9638eff 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.7.6" +version = "0.7.7" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -54,7 +54,7 @@ percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.11" postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" } -postgres-types = { version = "0.2.3", path = "../postgres-types" } +postgres-types = { version = "0.2.4", path = "../postgres-types" } socket2 = "0.4" tokio = { version = "1.0", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } From 54331183eaa6ee57f0dfeb01770b93360544c904 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 21 Aug 2022 15:37:10 -0400 Subject: [PATCH 200/420] Release postgres v0.19.4 --- postgres/CHANGELOG.md | 8 ++++++++ postgres/Cargo.toml | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index 5394da803..c467c8b73 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## v0.19.4 - 2022-08-21 + +## Added + +* Added `ToSql` and `FromSql` implementations for `[u8; N]` via the `array-impls` feature. +* Added support for `smol_str` 0.1 via the `with-smol_str-01` feature. +* Added `ToSql::encode_format` to support text encodings of parameters. + ## v0.19.3 - 2022-04-30 ### Added diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index b7f0e2ca5..2ca65941b 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.19.3" +version = "0.19.4" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -39,7 +39,7 @@ with-time-0_3 = ["tokio-postgres/with-time-0_3"] bytes = "1.0" fallible-iterator = "0.2" futures-util = { version = "0.3", features = ["sink"] } -tokio-postgres = { version = "0.7.6", path = "../tokio-postgres" } +tokio-postgres = { version = "0.7.7", path = "../tokio-postgres" } tokio = { version = "1.0", features = ["rt", "time"] } log = "0.4" From ed056758887464723881c3f6f21b0140746313de Mon Sep 17 00:00:00 2001 From: Matt Duch Date: Mon, 8 Aug 2022 19:22:06 -0500 Subject: [PATCH 201/420] derive generic FromSql/ToSql --- postgres-derive-test/src/composites.rs | 69 +++++++++++++++++++++++++- postgres-derive-test/src/lib.rs | 24 +++++++++ postgres-derive/src/fromsql.rs | 28 +++++++++-- postgres-derive/src/tosql.rs | 3 +- 4 files changed, 116 insertions(+), 8 deletions(-) diff --git a/postgres-derive-test/src/composites.rs b/postgres-derive-test/src/composites.rs index ed60bf48f..667633519 100644 --- a/postgres-derive-test/src/composites.rs +++ b/postgres-derive-test/src/composites.rs @@ -1,6 +1,6 @@ -use crate::test_type; +use crate::{test_type, test_type_asymmetric}; use postgres::{Client, NoTls}; -use postgres_types::{FromSql, ToSql, WrongType}; +use postgres_types::{FromSql, FromSqlOwned, ToSql, WrongType}; use std::error::Error; #[test] @@ -238,3 +238,68 @@ fn raw_ident_field() { test_type(&mut conn, "inventory_item", &[(item, "ROW('foo')")]); } + +#[test] +fn generics() { + #[derive(FromSql, Debug, PartialEq)] + struct InventoryItem + where + U: FromSqlOwned, + { + name: String, + supplier_id: T, + price: Option, + } + + // doesn't make sense to implement derived FromSql on a type with borrows + #[derive(ToSql, Debug, PartialEq)] + #[postgres(name = "InventoryItem")] + struct InventoryItemRef<'a, T: 'a + ToSql, U> + where + U: 'a + ToSql, + { + name: &'a str, + supplier_id: &'a T, + price: Option<&'a U>, + } + + const NAME: &str = "foobar"; + const SUPPLIER_ID: i32 = 100; + const PRICE: f64 = 15.50; + + let mut conn = Client::connect("user=postgres host=localhost port=5433", NoTls).unwrap(); + conn.batch_execute( + "CREATE TYPE pg_temp.\"InventoryItem\" AS ( + name TEXT, + supplier_id INT, + price DOUBLE PRECISION + );", + ) + .unwrap(); + + let item = InventoryItemRef { + name: NAME, + supplier_id: &SUPPLIER_ID, + price: Some(&PRICE), + }; + + let item_null = InventoryItemRef { + name: NAME, + supplier_id: &SUPPLIER_ID, + price: None, + }; + + test_type_asymmetric( + &mut conn, + "\"InventoryItem\"", + &[ + (item, "ROW('foobar', 100, 15.50)"), + (item_null, "ROW('foobar', 100, NULL)"), + ], + |t: &InventoryItemRef, f: &InventoryItem| { + t.name == f.name.as_str() + && t.supplier_id == &f.supplier_id + && t.price == f.price.as_ref() + }, + ); +} diff --git a/postgres-derive-test/src/lib.rs b/postgres-derive-test/src/lib.rs index 279ed1419..8bfd147fb 100644 --- a/postgres-derive-test/src/lib.rs +++ b/postgres-derive-test/src/lib.rs @@ -27,6 +27,30 @@ where } } +pub fn test_type_asymmetric( + conn: &mut Client, + sql_type: &str, + checks: &[(T, S)], + cmp: C, +) where + T: ToSql + Sync, + F: FromSqlOwned, + S: fmt::Display, + C: Fn(&T, &F) -> bool, +{ + for &(ref val, ref repr) in checks.iter() { + let stmt = conn + .prepare(&*format!("SELECT {}::{}", *repr, sql_type)) + .unwrap(); + let result: F = conn.query_one(&stmt, &[]).unwrap().get(0); + assert!(cmp(val, &result)); + + let stmt = conn.prepare(&*format!("SELECT $1::{}", sql_type)).unwrap(); + let result: F = conn.query_one(&stmt, &[val]).unwrap().get(0); + assert!(cmp(val, &result)); + } +} + #[test] fn compile_fail() { trybuild::TestCases::new().compile_fail("src/compile-fail/*.rs"); diff --git a/postgres-derive/src/fromsql.rs b/postgres-derive/src/fromsql.rs index c89cbb5e2..415343653 100644 --- a/postgres-derive/src/fromsql.rs +++ b/postgres-derive/src/fromsql.rs @@ -1,7 +1,10 @@ -use proc_macro2::TokenStream; +use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote}; use std::iter; -use syn::{Data, DataStruct, DeriveInput, Error, Fields, Ident}; +use syn::{ + Data, DataStruct, DeriveInput, Error, Fields, GenericParam, Generics, Ident, Lifetime, + LifetimeDef, +}; use crate::accepts; use crate::composites::Field; @@ -86,10 +89,13 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result { }; let ident = &input.ident; + let (generics, lifetime) = build_generics(&input.generics); + let (impl_generics, _, _) = generics.split_for_impl(); + let (_, ty_generics, where_clause) = input.generics.split_for_impl(); let out = quote! { - impl<'a> postgres_types::FromSql<'a> for #ident { - fn from_sql(_type: &postgres_types::Type, buf: &'a [u8]) - -> std::result::Result<#ident, + impl#impl_generics postgres_types::FromSql<#lifetime> for #ident#ty_generics #where_clause { + fn from_sql(_type: &postgres_types::Type, buf: &#lifetime [u8]) + -> std::result::Result<#ident#ty_generics, std::boxed::Box> { @@ -200,3 +206,15 @@ fn composite_body(ident: &Ident, fields: &[Field]) -> TokenStream { }) } } + +fn build_generics(source: &Generics) -> (Generics, Lifetime) { + let mut out = source.to_owned(); + // don't worry about lifetime name collisions, it doesn't make sense to derive FromSql on a struct with a lifetime + let lifetime = Lifetime::new("'a", Span::call_site()); + out.params.insert( + 0, + GenericParam::Lifetime(LifetimeDef::new(lifetime.to_owned())), + ); + + (out, lifetime) +} diff --git a/postgres-derive/src/tosql.rs b/postgres-derive/src/tosql.rs index 96f261385..299074f8d 100644 --- a/postgres-derive/src/tosql.rs +++ b/postgres-derive/src/tosql.rs @@ -82,8 +82,9 @@ pub fn expand_derive_tosql(input: DeriveInput) -> Result { }; let ident = &input.ident; + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); let out = quote! { - impl postgres_types::ToSql for #ident { + impl#impl_generics postgres_types::ToSql for #ident#ty_generics #where_clause { fn to_sql(&self, _type: &postgres_types::Type, buf: &mut postgres_types::private::BytesMut) From a78ce35d44e2c414d8a26074cb3a71c2471797ac Mon Sep 17 00:00:00 2001 From: Hirotaka Azuma Date: Fri, 26 Aug 2022 05:09:00 +0000 Subject: [PATCH 202/420] Support keepalive interval and retries. --- postgres/src/config.rs | 43 +++++++++++++ tokio-postgres/src/cancel_query.rs | 3 +- tokio-postgres/src/client.rs | 4 +- tokio-postgres/src/config.rs | 94 +++++++++++++++++++++++++--- tokio-postgres/src/connect.rs | 14 +++-- tokio-postgres/src/connect_socket.rs | 8 +-- tokio-postgres/src/keepalive.rs | 29 +++++++++ tokio-postgres/src/lib.rs | 1 + tokio-postgres/tests/test/parse.rs | 13 ++++ 9 files changed, 189 insertions(+), 20 deletions(-) create mode 100644 tokio-postgres/src/keepalive.rs diff --git a/postgres/src/config.rs b/postgres/src/config.rs index c8dffa330..f616dc689 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -48,6 +48,10 @@ use tokio_postgres::{Error, Socket}; /// This option is ignored when connecting with Unix sockets. Defaults to on. /// * `keepalives_idle` - The number of seconds of inactivity after which a keepalive message is sent to the server. /// This option is ignored when connecting with Unix sockets. Defaults to 2 hours. +/// * `keepalives_interval` - The time interval between TCP keepalive probes. +/// This option is ignored when connecting with Unix sockets. Available on neither Redox nor Solaris. +/// * `keepalives_retries` - The maximum number of TCP keepalive probes that will be sent before dropping a connection. +/// This option is ignored when connecting with Unix sockets. Available on neither Redox, Solaris nor Windows. /// * `target_session_attrs` - Specifies requirements of the session. If set to `read-write`, the client will check that /// the `transaction_read_write` session parameter is set to `on`. This can be used to connect to the primary server /// in a database cluster as opposed to the secondary read-only mirrors. Defaults to `all`. @@ -279,6 +283,45 @@ impl Config { self.config.get_keepalives_idle() } + /// Sets the time interval between TCP keepalive probes. + /// On Windows, this sets the value of the tcp_keepalive struct’s keepaliveinterval field. + /// + /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. + /// + /// Available on neither Redox nor Solaris. + #[cfg(not(any(target_os = "redox", target_os = "solaris")))] + pub fn keepalives_interval(&mut self, keepalives_interval: Duration) -> &mut Config { + self.config.keepalives_interval(keepalives_interval); + self + } + + /// Gets the time interval between TCP keepalive probes. + /// + /// Available on neither Redox nor Solaris. + #[cfg(not(any(target_os = "redox", target_os = "solaris")))] + pub fn get_keepalives_interval(&self) -> Option<&Duration> { + self.config.get_keepalives_interval() + } + + /// Sets the maximum number of TCP keepalive probes that will be sent before dropping a connection. + /// + /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. + /// + /// Available on neither Redox, Solaris nor Windows. + #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] + pub fn keepalives_retries(&mut self, keepalives_retries: u32) -> &mut Config { + self.config.keepalives_retries(keepalives_retries); + self + } + + /// Gets the maximum number of TCP keepalive probes that will be sent before dropping a connection. + /// + /// Available on neither Redox, Solaris nor Windows. + #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] + pub fn get_keepalives_retries(&self) -> Option<&u32> { + self.config.get_keepalives_retries() + } + /// Sets the requirements of the session. /// /// This can be used to connect to the primary server in a clustered database rather than one of the read-only diff --git a/tokio-postgres/src/cancel_query.rs b/tokio-postgres/src/cancel_query.rs index d7bb50474..b02729f85 100644 --- a/tokio-postgres/src/cancel_query.rs +++ b/tokio-postgres/src/cancel_query.rs @@ -38,8 +38,7 @@ where &config.host, config.port, config.connect_timeout, - config.keepalives, - config.keepalives_idle, + config.keepalive.as_ref(), ) .await?; diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 8444ff56a..1ed3964d5 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -4,6 +4,7 @@ use crate::config::Host; use crate::config::SslMode; use crate::connection::{Request, RequestMessages}; use crate::copy_out::CopyOutStream; +use crate::keepalive::KeepaliveConfig; use crate::query::RowStream; use crate::simple_query::SimpleQueryStream; #[cfg(feature = "runtime")] @@ -154,8 +155,7 @@ pub(crate) struct SocketConfig { pub host: Host, pub port: u16, pub connect_timeout: Option, - pub keepalives: bool, - pub keepalives_idle: Duration, + pub keepalive: Option, } /// An asynchronous PostgreSQL client. diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 2c29d629c..5a0c639e1 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -3,6 +3,7 @@ #[cfg(feature = "runtime")] use crate::connect::connect; use crate::connect_raw::connect_raw; +use crate::keepalive::KeepaliveConfig; #[cfg(feature = "runtime")] use crate::tls::MakeTlsConnect; use crate::tls::TlsConnect; @@ -99,6 +100,10 @@ pub enum Host { /// This option is ignored when connecting with Unix sockets. Defaults to on. /// * `keepalives_idle` - The number of seconds of inactivity after which a keepalive message is sent to the server. /// This option is ignored when connecting with Unix sockets. Defaults to 2 hours. +/// * `keepalives_interval` - The time interval between TCP keepalive probes. +/// This option is ignored when connecting with Unix sockets. Available on neither Redox nor Solaris. +/// * `keepalives_retries` - The maximum number of TCP keepalive probes that will be sent before dropping a connection. +/// This option is ignored when connecting with Unix sockets. Available on neither Redox, Solaris nor Windows. /// * `target_session_attrs` - Specifies requirements of the session. If set to `read-write`, the client will check that /// the `transaction_read_write` session parameter is set to `on`. This can be used to connect to the primary server /// in a database cluster as opposed to the secondary read-only mirrors. Defaults to `all`. @@ -156,7 +161,7 @@ pub struct Config { pub(crate) port: Vec, pub(crate) connect_timeout: Option, pub(crate) keepalives: bool, - pub(crate) keepalives_idle: Duration, + pub(crate) keepalive_config: KeepaliveConfig, pub(crate) target_session_attrs: TargetSessionAttrs, pub(crate) channel_binding: ChannelBinding, } @@ -170,6 +175,13 @@ impl Default for Config { impl Config { /// Creates a new configuration. pub fn new() -> Config { + let keepalive_config = KeepaliveConfig { + idle: Duration::from_secs(2 * 60 * 60), + #[cfg(not(any(target_os = "redox", target_os = "solaris")))] + interval: None, + #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] + retries: None, + }; Config { user: None, password: None, @@ -181,7 +193,7 @@ impl Config { port: vec![], connect_timeout: None, keepalives: true, - keepalives_idle: Duration::from_secs(2 * 60 * 60), + keepalive_config, target_session_attrs: TargetSessionAttrs::Any, channel_binding: ChannelBinding::Prefer, } @@ -347,14 +359,53 @@ impl Config { /// /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. Defaults to 2 hours. pub fn keepalives_idle(&mut self, keepalives_idle: Duration) -> &mut Config { - self.keepalives_idle = keepalives_idle; + self.keepalive_config.idle = keepalives_idle; self } /// Gets the configured amount of idle time before a keepalive packet will /// be sent on the connection. pub fn get_keepalives_idle(&self) -> Duration { - self.keepalives_idle + self.keepalive_config.idle + } + + /// Sets the time interval between TCP keepalive probes. + /// On Windows, this sets the value of the tcp_keepalive struct’s keepaliveinterval field. + /// + /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. + /// + /// Available on neither Redox nor Solaris. + #[cfg(not(any(target_os = "redox", target_os = "solaris")))] + pub fn keepalives_interval(&mut self, keepalives_interval: Duration) -> &mut Config { + self.keepalive_config.interval = Some(keepalives_interval); + self + } + + /// Gets the time interval between TCP keepalive probes. + /// + /// Available on neither Redox nor Solaris. + #[cfg(not(any(target_os = "redox", target_os = "solaris")))] + pub fn get_keepalives_interval(&self) -> Option<&Duration> { + self.keepalive_config.interval.as_ref() + } + + /// Sets the maximum number of TCP keepalive probes that will be sent before dropping a connection. + /// + /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. + /// + /// Available on neither Redox, Solaris nor Windows. + #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] + pub fn keepalives_retries(&mut self, keepalives_retries: u32) -> &mut Config { + self.keepalive_config.retries = Some(keepalives_retries); + self + } + + /// Gets the maximum number of TCP keepalive probes that will be sent before dropping a connection. + /// + /// Available on neither Redox, Solaris nor Windows. + #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] + pub fn get_keepalives_retries(&self) -> Option<&u32> { + self.keepalive_config.retries.as_ref() } /// Sets the requirements of the session. @@ -451,6 +502,22 @@ impl Config { self.keepalives_idle(Duration::from_secs(keepalives_idle as u64)); } } + #[cfg(not(any(target_os = "redox", target_os = "solaris")))] + "keepalives_interval" => { + let keepalives_interval = value.parse::().map_err(|_| { + Error::config_parse(Box::new(InvalidValue("keepalives_interval"))) + })?; + if keepalives_interval > 0 { + self.keepalives_interval(Duration::from_secs(keepalives_interval as u64)); + } + } + #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] + "keepalives_retries" => { + let keepalives_retries = value.parse::().map_err(|_| { + Error::config_parse(Box::new(InvalidValue("keepalives_retries"))) + })?; + self.keepalives_retries(keepalives_retries); + } "target_session_attrs" => { let target_session_attrs = match value { "any" => TargetSessionAttrs::Any, @@ -534,8 +601,8 @@ impl fmt::Debug for Config { } } - f.debug_struct("Config") - .field("user", &self.user) + let mut ds = f.debug_struct("Config"); + ds.field("user", &self.user) .field("password", &self.password.as_ref().map(|_| Redaction {})) .field("dbname", &self.dbname) .field("options", &self.options) @@ -545,8 +612,19 @@ impl fmt::Debug for Config { .field("port", &self.port) .field("connect_timeout", &self.connect_timeout) .field("keepalives", &self.keepalives) - .field("keepalives_idle", &self.keepalives_idle) - .field("target_session_attrs", &self.target_session_attrs) + .field("keepalives_idle", &self.keepalive_config.idle); + + #[cfg(not(any(target_os = "redox", target_os = "solaris")))] + { + ds.field("keepalives_interval", &self.keepalive_config.interval); + } + + #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] + { + ds.field("keepalives_retries", &self.keepalive_config.retries); + } + + ds.field("target_session_attrs", &self.target_session_attrs) .field("channel_binding", &self.channel_binding) .finish() } diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 88faafe6b..97a00c812 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -65,8 +65,11 @@ where host, port, config.connect_timeout, - config.keepalives, - config.keepalives_idle, + if config.keepalives { + Some(&config.keepalive_config) + } else { + None + }, ) .await?; let (mut client, mut connection) = connect_raw(socket, tls, config).await?; @@ -115,8 +118,11 @@ where host: host.clone(), port, connect_timeout: config.connect_timeout, - keepalives: config.keepalives, - keepalives_idle: config.keepalives_idle, + keepalive: if config.keepalives { + Some(config.keepalive_config.clone()) + } else { + None + }, }); Ok((client, connection)) diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 474676908..19d01d87a 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -1,4 +1,5 @@ use crate::config::Host; +use crate::keepalive::KeepaliveConfig; use crate::{Error, Socket}; use socket2::{SockRef, TcpKeepalive}; use std::future::Future; @@ -13,8 +14,7 @@ pub(crate) async fn connect_socket( host: &Host, port: u16, connect_timeout: Option, - keepalives: bool, - keepalives_idle: Duration, + keepalive_config: Option<&KeepaliveConfig>, ) -> Result { match host { Host::Tcp(host) => { @@ -35,9 +35,9 @@ pub(crate) async fn connect_socket( }; stream.set_nodelay(true).map_err(Error::connect)?; - if keepalives { + if let Some(keepalive_config) = keepalive_config { SockRef::from(&stream) - .set_tcp_keepalive(&TcpKeepalive::new().with_time(keepalives_idle)) + .set_tcp_keepalive(&TcpKeepalive::from(keepalive_config)) .map_err(Error::connect)?; } diff --git a/tokio-postgres/src/keepalive.rs b/tokio-postgres/src/keepalive.rs new file mode 100644 index 000000000..4b61d2099 --- /dev/null +++ b/tokio-postgres/src/keepalive.rs @@ -0,0 +1,29 @@ +use socket2::TcpKeepalive; +use std::time::Duration; + +#[derive(Clone, PartialEq, Eq)] +pub(crate) struct KeepaliveConfig { + pub idle: Duration, + #[cfg(not(any(target_os = "redox", target_os = "solaris")))] + pub interval: Option, + #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] + pub retries: Option, +} + +impl From<&KeepaliveConfig> for TcpKeepalive { + fn from(keepalive_config: &KeepaliveConfig) -> Self { + let mut tcp_keepalive = Self::new().with_time(keepalive_config.idle); + + #[cfg(not(any(target_os = "redox", target_os = "solaris")))] + if let Some(interval) = keepalive_config.interval { + tcp_keepalive = tcp_keepalive.with_interval(interval); + } + + #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] + if let Some(retries) = keepalive_config.retries { + tcp_keepalive = tcp_keepalive.with_retries(retries); + } + + tcp_keepalive + } +} diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 4056819fd..bd4d7b8ce 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -163,6 +163,7 @@ mod copy_in; mod copy_out; pub mod error; mod generic_client; +mod keepalive; mod maybe_tls_stream; mod portal; mod prepare; diff --git a/tokio-postgres/tests/test/parse.rs b/tokio-postgres/tests/test/parse.rs index a7a9625b2..575d962a2 100644 --- a/tokio-postgres/tests/test/parse.rs +++ b/tokio-postgres/tests/test/parse.rs @@ -36,6 +36,19 @@ fn settings() { ); } +#[test] +#[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] +fn keepalive_settings() { + check( + "keepalives=1 keepalives_idle=15 keepalives_interval=5 keepalives_retries=9", + Config::new() + .keepalives(true) + .keepalives_idle(Duration::from_secs(15)) + .keepalives_interval(Duration::from_secs(5)) + .keepalives_retries(9), + ); +} + #[test] fn url() { check("postgresql://", &Config::new()); From b5a53960b18197f7220199568f33063bb496a08c Mon Sep 17 00:00:00 2001 From: Hirotaka Azuma Date: Fri, 26 Aug 2022 19:27:06 +0000 Subject: [PATCH 203/420] Review fix: Define features regardless of platform and do nothing if not supported. --- postgres/src/config.rs | 16 ++---------- tokio-postgres/src/config.rs | 41 ++++++------------------------ tokio-postgres/src/keepalive.rs | 2 -- tokio-postgres/tests/test/parse.rs | 1 - 4 files changed, 10 insertions(+), 50 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index f616dc689..7d02affd2 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -49,9 +49,9 @@ use tokio_postgres::{Error, Socket}; /// * `keepalives_idle` - The number of seconds of inactivity after which a keepalive message is sent to the server. /// This option is ignored when connecting with Unix sockets. Defaults to 2 hours. /// * `keepalives_interval` - The time interval between TCP keepalive probes. -/// This option is ignored when connecting with Unix sockets. Available on neither Redox nor Solaris. +/// This option is ignored when connecting with Unix sockets. /// * `keepalives_retries` - The maximum number of TCP keepalive probes that will be sent before dropping a connection. -/// This option is ignored when connecting with Unix sockets. Available on neither Redox, Solaris nor Windows. +/// This option is ignored when connecting with Unix sockets. /// * `target_session_attrs` - Specifies requirements of the session. If set to `read-write`, the client will check that /// the `transaction_read_write` session parameter is set to `on`. This can be used to connect to the primary server /// in a database cluster as opposed to the secondary read-only mirrors. Defaults to `all`. @@ -287,18 +287,12 @@ impl Config { /// On Windows, this sets the value of the tcp_keepalive struct’s keepaliveinterval field. /// /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. - /// - /// Available on neither Redox nor Solaris. - #[cfg(not(any(target_os = "redox", target_os = "solaris")))] pub fn keepalives_interval(&mut self, keepalives_interval: Duration) -> &mut Config { self.config.keepalives_interval(keepalives_interval); self } /// Gets the time interval between TCP keepalive probes. - /// - /// Available on neither Redox nor Solaris. - #[cfg(not(any(target_os = "redox", target_os = "solaris")))] pub fn get_keepalives_interval(&self) -> Option<&Duration> { self.config.get_keepalives_interval() } @@ -306,18 +300,12 @@ impl Config { /// Sets the maximum number of TCP keepalive probes that will be sent before dropping a connection. /// /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. - /// - /// Available on neither Redox, Solaris nor Windows. - #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] pub fn keepalives_retries(&mut self, keepalives_retries: u32) -> &mut Config { self.config.keepalives_retries(keepalives_retries); self } /// Gets the maximum number of TCP keepalive probes that will be sent before dropping a connection. - /// - /// Available on neither Redox, Solaris nor Windows. - #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] pub fn get_keepalives_retries(&self) -> Option<&u32> { self.config.get_keepalives_retries() } diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 5a0c639e1..6931e012d 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -101,9 +101,9 @@ pub enum Host { /// * `keepalives_idle` - The number of seconds of inactivity after which a keepalive message is sent to the server. /// This option is ignored when connecting with Unix sockets. Defaults to 2 hours. /// * `keepalives_interval` - The time interval between TCP keepalive probes. -/// This option is ignored when connecting with Unix sockets. Available on neither Redox nor Solaris. +/// This option is ignored when connecting with Unix sockets. /// * `keepalives_retries` - The maximum number of TCP keepalive probes that will be sent before dropping a connection. -/// This option is ignored when connecting with Unix sockets. Available on neither Redox, Solaris nor Windows. +/// This option is ignored when connecting with Unix sockets. /// * `target_session_attrs` - Specifies requirements of the session. If set to `read-write`, the client will check that /// the `transaction_read_write` session parameter is set to `on`. This can be used to connect to the primary server /// in a database cluster as opposed to the secondary read-only mirrors. Defaults to `all`. @@ -177,9 +177,7 @@ impl Config { pub fn new() -> Config { let keepalive_config = KeepaliveConfig { idle: Duration::from_secs(2 * 60 * 60), - #[cfg(not(any(target_os = "redox", target_os = "solaris")))] interval: None, - #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] retries: None, }; Config { @@ -373,18 +371,12 @@ impl Config { /// On Windows, this sets the value of the tcp_keepalive struct’s keepaliveinterval field. /// /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. - /// - /// Available on neither Redox nor Solaris. - #[cfg(not(any(target_os = "redox", target_os = "solaris")))] pub fn keepalives_interval(&mut self, keepalives_interval: Duration) -> &mut Config { self.keepalive_config.interval = Some(keepalives_interval); self } /// Gets the time interval between TCP keepalive probes. - /// - /// Available on neither Redox nor Solaris. - #[cfg(not(any(target_os = "redox", target_os = "solaris")))] pub fn get_keepalives_interval(&self) -> Option<&Duration> { self.keepalive_config.interval.as_ref() } @@ -392,18 +384,12 @@ impl Config { /// Sets the maximum number of TCP keepalive probes that will be sent before dropping a connection. /// /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. - /// - /// Available on neither Redox, Solaris nor Windows. - #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] pub fn keepalives_retries(&mut self, keepalives_retries: u32) -> &mut Config { self.keepalive_config.retries = Some(keepalives_retries); self } /// Gets the maximum number of TCP keepalive probes that will be sent before dropping a connection. - /// - /// Available on neither Redox, Solaris nor Windows. - #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] pub fn get_keepalives_retries(&self) -> Option<&u32> { self.keepalive_config.retries.as_ref() } @@ -502,7 +488,6 @@ impl Config { self.keepalives_idle(Duration::from_secs(keepalives_idle as u64)); } } - #[cfg(not(any(target_os = "redox", target_os = "solaris")))] "keepalives_interval" => { let keepalives_interval = value.parse::().map_err(|_| { Error::config_parse(Box::new(InvalidValue("keepalives_interval"))) @@ -511,7 +496,6 @@ impl Config { self.keepalives_interval(Duration::from_secs(keepalives_interval as u64)); } } - #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] "keepalives_retries" => { let keepalives_retries = value.parse::().map_err(|_| { Error::config_parse(Box::new(InvalidValue("keepalives_retries"))) @@ -601,8 +585,8 @@ impl fmt::Debug for Config { } } - let mut ds = f.debug_struct("Config"); - ds.field("user", &self.user) + f.debug_struct("Config") + .field("user", &self.user) .field("password", &self.password.as_ref().map(|_| Redaction {})) .field("dbname", &self.dbname) .field("options", &self.options) @@ -612,19 +596,10 @@ impl fmt::Debug for Config { .field("port", &self.port) .field("connect_timeout", &self.connect_timeout) .field("keepalives", &self.keepalives) - .field("keepalives_idle", &self.keepalive_config.idle); - - #[cfg(not(any(target_os = "redox", target_os = "solaris")))] - { - ds.field("keepalives_interval", &self.keepalive_config.interval); - } - - #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] - { - ds.field("keepalives_retries", &self.keepalive_config.retries); - } - - ds.field("target_session_attrs", &self.target_session_attrs) + .field("keepalives_idle", &self.keepalive_config.idle) + .field("keepalives_interval", &self.keepalive_config.interval) + .field("keepalives_retries", &self.keepalive_config.retries) + .field("target_session_attrs", &self.target_session_attrs) .field("channel_binding", &self.channel_binding) .finish() } diff --git a/tokio-postgres/src/keepalive.rs b/tokio-postgres/src/keepalive.rs index 4b61d2099..74f453985 100644 --- a/tokio-postgres/src/keepalive.rs +++ b/tokio-postgres/src/keepalive.rs @@ -4,9 +4,7 @@ use std::time::Duration; #[derive(Clone, PartialEq, Eq)] pub(crate) struct KeepaliveConfig { pub idle: Duration, - #[cfg(not(any(target_os = "redox", target_os = "solaris")))] pub interval: Option, - #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] pub retries: Option, } diff --git a/tokio-postgres/tests/test/parse.rs b/tokio-postgres/tests/test/parse.rs index 575d962a2..2c11899ca 100644 --- a/tokio-postgres/tests/test/parse.rs +++ b/tokio-postgres/tests/test/parse.rs @@ -37,7 +37,6 @@ fn settings() { } #[test] -#[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] fn keepalive_settings() { check( "keepalives=1 keepalives_idle=15 keepalives_interval=5 keepalives_retries=9", From b46ea89c42441187d15cd70e651907e29d6338c8 Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Fri, 26 Aug 2022 13:46:04 -0700 Subject: [PATCH 204/420] Add hostaddr support --- tokio-postgres/src/config.rs | 70 +++++++++++++++++++++++++++++++++++ tokio-postgres/src/connect.rs | 23 +++++++++++- 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 2c29d629c..f29eed2b1 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -12,6 +12,7 @@ use crate::{Client, Connection, Error}; use std::borrow::Cow; #[cfg(unix)] use std::ffi::OsStr; +use std::ops::Deref; #[cfg(unix)] use std::os::unix::ffi::OsStrExt; #[cfg(unix)] @@ -90,6 +91,17 @@ 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. +/// * `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, +/// - or if host specifies an IP address, that value will be used directly. +/// Using `hostaddr` allows the application to avoid a host name look-up, which might be important in applications +/// with time constraints. However, a host name is required for verify-full SSL certificate verification. +/// Note that `host` is always required regardless of whether `hostaddr` is present. +/// * If `host` is specified without `hostaddr`, a host name lookup occurs; +/// * If both `host` and `hostaddr` are specified, the value for `hostaddr` gives the server network address. +/// The value for `host` is ignored unless the authentication method requires it, +/// in which case it will be used as the host name. /// * `port` - The port to connect to. Multiple ports can be specified, separated by commas. The number of ports must be /// either 1, in which case it will be used for all hosts, or the same as the number of hosts. Defaults to 5432 if /// omitted or the empty string. @@ -117,6 +129,10 @@ pub enum Host { /// ``` /// /// ```not_rust +/// host=host1,host2,host3 port=1234,,5678 hostaddr=127.0.0.1,127.0.0.2,127.0.0.3 user=postgres target_session_attrs=read-write +/// ``` +/// +/// ```not_rust /// host=host1,host2,host3 port=1234,,5678 user=postgres target_session_attrs=read-write /// ``` /// @@ -153,6 +169,7 @@ pub struct Config { pub(crate) application_name: Option, pub(crate) ssl_mode: SslMode, pub(crate) host: Vec, + pub(crate) hostaddr: Vec, pub(crate) port: Vec, pub(crate) connect_timeout: Option, pub(crate) keepalives: bool, @@ -178,6 +195,7 @@ impl Config { application_name: None, ssl_mode: SslMode::Prefer, host: vec![], + hostaddr: vec![], port: vec![], connect_timeout: None, keepalives: true, @@ -288,6 +306,11 @@ impl Config { &self.host } + /// Gets the hostaddrs that have been added to the configuration with `hostaddr`. + pub fn get_hostaddrs(&self) -> &[String] { + self.hostaddr.deref() + } + /// Adds a Unix socket host to the configuration. /// /// Unlike `host`, this method allows non-UTF8 paths. @@ -300,6 +323,15 @@ impl Config { self } + /// Adds a hostaddr to the configuration. + /// + /// Multiple hostaddrs can be specified by calling this method multiple times, and each will be tried in order. + /// There must be either no hostaddrs, or the same number of hostaddrs as hosts. + pub fn hostaddr(&mut self, hostaddr: &str) -> &mut Config { + self.hostaddr.push(hostaddr.to_string()); + self + } + /// Adds a port to the configuration. /// /// Multiple ports can be specified by calling this method multiple times. There must either be no ports, in which @@ -418,6 +450,11 @@ impl Config { self.host(host); } } + "hostaddr" => { + for hostaddr in value.split(',') { + self.hostaddr(hostaddr); + } + } "port" => { for port in value.split(',') { let port = if port.is_empty() { @@ -542,6 +579,7 @@ impl fmt::Debug for Config { .field("application_name", &self.application_name) .field("ssl_mode", &self.ssl_mode) .field("host", &self.host) + .field("hostaddr", &self.hostaddr) .field("port", &self.port) .field("connect_timeout", &self.connect_timeout) .field("keepalives", &self.keepalives) @@ -922,3 +960,35 @@ impl<'a> UrlParser<'a> { .map_err(|e| Error::config_parse(e.into())) } } + +#[cfg(test)] +mod tests { + use crate::{config::Host, Config}; + + #[test] + fn test_simple_parsing() { + let s = "user=pass_user dbname=postgres host=host1,host2 hostaddr=127.0.0.1,127.0.0.2 port=26257"; + let config = s.parse::().unwrap(); + assert_eq!(Some("pass_user"), config.get_user()); + assert_eq!(Some("postgres"), config.get_dbname()); + assert_eq!( + [ + Host::Tcp("host1".to_string()), + Host::Tcp("host2".to_string()) + ], + config.get_hosts(), + ); + + assert_eq!(["127.0.0.1", "127.0.0.2"], config.get_hostaddrs(),); + + assert_eq!(1, 1); + } + + #[test] + fn test_empty_hostaddrs() { + let s = + "user=pass_user dbname=postgres host=host1,host2,host3 hostaddr=127.0.0.1,,127.0.0.2"; + let config = s.parse::().unwrap(); + assert_eq!(["127.0.0.1", "", "127.0.0.2"], config.get_hostaddrs(),); + } +} diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 88faafe6b..e8ac29b42 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -23,6 +23,15 @@ where return Err(Error::config("invalid number of ports".into())); } + if !config.hostaddr.is_empty() && config.hostaddr.len() != config.host.len() { + let msg = format!( + "invalid number of hostaddrs ({}). Possible values: 0 or number of hosts ({})", + config.hostaddr.len(), + config.host.len(), + ); + return Err(Error::config(msg.into())); + } + let mut error = None; for (i, host) in config.host.iter().enumerate() { let port = config @@ -32,18 +41,28 @@ where .copied() .unwrap_or(5432); + // The value of host is always used as the hostname for TLS validation. let hostname = match host { Host::Tcp(host) => host.as_str(), // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter #[cfg(unix)] Host::Unix(_) => "", }; - let tls = tls .make_tls_connect(hostname) .map_err(|e| Error::tls(e.into()))?; - match connect_once(host, port, tls, config).await { + // If both host and hostaddr are specified, the value of hostaddr is used to to establish the TCP connection. + let hostaddr = match host { + Host::Tcp(_hostname) => match config.hostaddr.get(i) { + Some(hostaddr) if hostaddr.is_empty() => Host::Tcp(hostaddr.clone()), + _ => host.clone(), + }, + #[cfg(unix)] + Host::Unix(_v) => host.clone(), + }; + + match connect_once(&hostaddr, port, tls, config).await { Ok((client, connection)) => return Ok((client, connection)), Err(e) => error = Some(e), } From a97e17b51e2e5ebbedae8d5ad501db9fc71e179a Mon Sep 17 00:00:00 2001 From: Hirotaka Azuma Date: Sat, 27 Aug 2022 13:46:22 +0000 Subject: [PATCH 205/420] Fix CI error: Prevent "unused imports" in --no-default-features. --- tokio-postgres/src/client.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 1ed3964d5..ad5aa2866 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -4,6 +4,7 @@ use crate::config::Host; use crate::config::SslMode; use crate::connection::{Request, RequestMessages}; use crate::copy_out::CopyOutStream; +#[cfg(feature = "runtime")] use crate::keepalive::KeepaliveConfig; use crate::query::RowStream; use crate::simple_query::SimpleQueryStream; From 0fcd0c26a59420468999571bd418d57b8e2ad754 Mon Sep 17 00:00:00 2001 From: Hirotaka Azuma Date: Sat, 27 Aug 2022 13:56:17 +0000 Subject: [PATCH 206/420] Review fix: get_keepalives_{interval,retries} returns copied Option. --- postgres/src/config.rs | 4 ++-- tokio-postgres/src/config.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index 7d02affd2..b541ec846 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -293,7 +293,7 @@ impl Config { } /// Gets the time interval between TCP keepalive probes. - pub fn get_keepalives_interval(&self) -> Option<&Duration> { + pub fn get_keepalives_interval(&self) -> Option { self.config.get_keepalives_interval() } @@ -306,7 +306,7 @@ impl Config { } /// Gets the maximum number of TCP keepalive probes that will be sent before dropping a connection. - pub fn get_keepalives_retries(&self) -> Option<&u32> { + pub fn get_keepalives_retries(&self) -> Option { self.config.get_keepalives_retries() } diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 6931e012d..e8d057640 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -377,8 +377,8 @@ impl Config { } /// Gets the time interval between TCP keepalive probes. - pub fn get_keepalives_interval(&self) -> Option<&Duration> { - self.keepalive_config.interval.as_ref() + pub fn get_keepalives_interval(&self) -> Option { + self.keepalive_config.interval.as_ref().copied() } /// Sets the maximum number of TCP keepalive probes that will be sent before dropping a connection. @@ -390,8 +390,8 @@ impl Config { } /// Gets the maximum number of TCP keepalive probes that will be sent before dropping a connection. - pub fn get_keepalives_retries(&self) -> Option<&u32> { - self.keepalive_config.retries.as_ref() + pub fn get_keepalives_retries(&self) -> Option { + self.keepalive_config.retries.as_ref().copied() } /// Sets the requirements of the session. From 4882ecc2de0b02183f4c69249d59178ec5e11f40 Mon Sep 17 00:00:00 2001 From: Hirotaka Azuma Date: Sat, 27 Aug 2022 13:58:31 +0000 Subject: [PATCH 207/420] Review fix: get_connect_timeout returns copied Option. --- postgres/src/config.rs | 2 +- tokio-postgres/src/config.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index b541ec846..db8d6613c 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -252,7 +252,7 @@ impl Config { /// Gets the connection timeout, if one has been set with the /// `connect_timeout` method. - pub fn get_connect_timeout(&self) -> Option<&Duration> { + pub fn get_connect_timeout(&self) -> Option { self.config.get_connect_timeout() } diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index e8d057640..3a11e99ca 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -336,8 +336,8 @@ impl Config { /// Gets the connection timeout, if one has been set with the /// `connect_timeout` method. - pub fn get_connect_timeout(&self) -> Option<&Duration> { - self.connect_timeout.as_ref() + pub fn get_connect_timeout(&self) -> Option { + self.connect_timeout.as_ref().copied() } /// Controls the use of TCP keepalive. From 5551b3e6cdd81c18d5ffb13ee5478fcd0e551475 Mon Sep 17 00:00:00 2001 From: Hirotaka Azuma Date: Sat, 27 Aug 2022 14:18:27 +0000 Subject: [PATCH 208/420] Revert "Review fix: get_connect_timeout returns copied Option." This reverts commit 4882ecc2de0b02183f4c69249d59178ec5e11f40. --- postgres/src/config.rs | 2 +- tokio-postgres/src/config.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index db8d6613c..b541ec846 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -252,7 +252,7 @@ impl Config { /// Gets the connection timeout, if one has been set with the /// `connect_timeout` method. - pub fn get_connect_timeout(&self) -> Option { + pub fn get_connect_timeout(&self) -> Option<&Duration> { self.config.get_connect_timeout() } diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 3a11e99ca..e8d057640 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -336,8 +336,8 @@ impl Config { /// Gets the connection timeout, if one has been set with the /// `connect_timeout` method. - pub fn get_connect_timeout(&self) -> Option { - self.connect_timeout.as_ref().copied() + pub fn get_connect_timeout(&self) -> Option<&Duration> { + self.connect_timeout.as_ref() } /// Controls the use of TCP keepalive. From d7ccbb3d4255fe7906703f1edd4017915095f87d Mon Sep 17 00:00:00 2001 From: Hirotaka Azuma Date: Sat, 27 Aug 2022 14:19:01 +0000 Subject: [PATCH 209/420] Review fix: Avoid redundant function calls. --- tokio-postgres/src/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index e8d057640..5b364ec06 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -378,7 +378,7 @@ impl Config { /// Gets the time interval between TCP keepalive probes. pub fn get_keepalives_interval(&self) -> Option { - self.keepalive_config.interval.as_ref().copied() + self.keepalive_config.interval } /// Sets the maximum number of TCP keepalive probes that will be sent before dropping a connection. @@ -391,7 +391,7 @@ impl Config { /// Gets the maximum number of TCP keepalive probes that will be sent before dropping a connection. pub fn get_keepalives_retries(&self) -> Option { - self.keepalive_config.retries.as_ref().copied() + self.keepalive_config.retries } /// Sets the requirements of the session. From 3c9315e3200f5eb99bb5a9b5998aca555951d691 Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Sat, 27 Aug 2022 11:40:57 -0700 Subject: [PATCH 210/420] IpAddr + try hostaddr first --- tokio-postgres/src/config.rs | 36 ++++++++++-------- tokio-postgres/src/connect.rs | 61 +++++++++++++++++++------------ tokio-postgres/tests/test/main.rs | 52 ++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 39 deletions(-) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 0c62b5030..34accdbe8 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -13,6 +13,7 @@ use crate::{Client, Connection, Error}; use std::borrow::Cow; #[cfg(unix)] use std::ffi::OsStr; +use std::net::IpAddr; use std::ops::Deref; #[cfg(unix)] use std::os::unix::ffi::OsStrExt; @@ -98,7 +99,9 @@ pub enum Host { /// - or if host specifies an IP address, that value will be used directly. /// Using `hostaddr` allows the application to avoid a host name look-up, which might be important in applications /// with time constraints. However, a host name is required for verify-full SSL certificate verification. -/// Note that `host` is always required regardless of whether `hostaddr` is present. +/// Specifically: +/// * If `hostaddr` is specified without `host`, the value for `hostaddr` gives the server network address. +/// The connection attempt will fail if the authentication method requires a host name; /// * If `host` is specified without `hostaddr`, a host name lookup occurs; /// * If both `host` and `hostaddr` are specified, the value for `hostaddr` gives the server network address. /// The value for `host` is ignored unless the authentication method requires it, @@ -174,7 +177,7 @@ pub struct Config { pub(crate) application_name: Option, pub(crate) ssl_mode: SslMode, pub(crate) host: Vec, - pub(crate) hostaddr: Vec, + pub(crate) hostaddr: Vec, pub(crate) port: Vec, pub(crate) connect_timeout: Option, pub(crate) keepalives: bool, @@ -317,7 +320,7 @@ impl Config { } /// Gets the hostaddrs that have been added to the configuration with `hostaddr`. - pub fn get_hostaddrs(&self) -> &[String] { + pub fn get_hostaddrs(&self) -> &[IpAddr] { self.hostaddr.deref() } @@ -337,8 +340,8 @@ impl Config { /// /// Multiple hostaddrs can be specified by calling this method multiple times, and each will be tried in order. /// There must be either no hostaddrs, or the same number of hostaddrs as hosts. - pub fn hostaddr(&mut self, hostaddr: &str) -> &mut Config { - self.hostaddr.push(hostaddr.to_string()); + pub fn hostaddr(&mut self, hostaddr: IpAddr) -> &mut Config { + self.hostaddr.push(hostaddr); self } @@ -489,7 +492,10 @@ impl Config { } "hostaddr" => { for hostaddr in value.split(',') { - self.hostaddr(hostaddr); + let addr = hostaddr + .parse() + .map_err(|_| Error::config_parse(Box::new(InvalidValue("hostaddr"))))?; + self.hostaddr(addr); } } "port" => { @@ -1016,6 +1022,8 @@ impl<'a> UrlParser<'a> { #[cfg(test)] mod tests { + use std::net::IpAddr; + use crate::{config::Host, Config}; #[test] @@ -1032,16 +1040,14 @@ mod tests { config.get_hosts(), ); - assert_eq!(["127.0.0.1", "127.0.0.2"], config.get_hostaddrs(),); + assert_eq!( + [ + "127.0.0.1".parse::().unwrap(), + "127.0.0.2".parse::().unwrap() + ], + config.get_hostaddrs(), + ); assert_eq!(1, 1); } - - #[test] - fn test_empty_hostaddrs() { - let s = - "user=pass_user dbname=postgres host=host1,host2,host3 hostaddr=127.0.0.1,,127.0.0.2"; - let config = s.parse::().unwrap(); - assert_eq!(["127.0.0.1", "", "127.0.0.2"], config.get_hostaddrs(),); - } } diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index c36677234..ee1dc1c76 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -5,8 +5,8 @@ use crate::connect_socket::connect_socket; use crate::tls::{MakeTlsConnect, TlsConnect}; use crate::{Client, Config, Connection, Error, SimpleQueryMessage, Socket}; use futures_util::{future, pin_mut, Future, FutureExt, Stream}; -use std::io; use std::task::Poll; +use std::{cmp, io}; pub async fn connect( mut tls: T, @@ -15,25 +15,35 @@ pub async fn connect( where T: MakeTlsConnect, { - if config.host.is_empty() { - return Err(Error::config("host missing".into())); + if config.host.is_empty() && config.hostaddr.is_empty() { + return Err(Error::config("both host and hostaddr are missing".into())); } - if config.port.len() > 1 && config.port.len() != config.host.len() { - return Err(Error::config("invalid number of ports".into())); - } - - if !config.hostaddr.is_empty() && config.hostaddr.len() != config.host.len() { + if !config.host.is_empty() + && !config.hostaddr.is_empty() + && config.host.len() != config.hostaddr.len() + { let msg = format!( - "invalid number of hostaddrs ({}). Possible values: 0 or number of hosts ({})", - config.hostaddr.len(), + "number of hosts ({}) is different from number of hostaddrs ({})", config.host.len(), + config.hostaddr.len(), ); return Err(Error::config(msg.into())); } + // At this point, either one of the following two scenarios could happen: + // (1) either config.host or config.hostaddr must be empty; + // (2) if both config.host and config.hostaddr are NOT empty; their lengths must be equal. + let num_hosts = cmp::max(config.host.len(), config.hostaddr.len()); + + if config.port.len() > 1 && config.port.len() != num_hosts { + return Err(Error::config("invalid number of ports".into())); + } + let mut error = None; - for (i, host) in config.host.iter().enumerate() { + for i in 0..num_hosts { + let host = config.host.get(i); + let hostaddr = config.hostaddr.get(i); let port = config .port .get(i) @@ -42,27 +52,30 @@ where .unwrap_or(5432); // The value of host is always used as the hostname for TLS validation. + // postgres doesn't support TLS over unix sockets, so the choice for Host::Unix variant here doesn't matter let hostname = match host { - Host::Tcp(host) => host.as_str(), - // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter - #[cfg(unix)] - Host::Unix(_) => "", + Some(Host::Tcp(host)) => host.as_str(), + _ => "", }; let tls = tls .make_tls_connect(hostname) .map_err(|e| Error::tls(e.into()))?; - // If both host and hostaddr are specified, the value of hostaddr is used to to establish the TCP connection. - let hostaddr = match host { - Host::Tcp(_hostname) => match config.hostaddr.get(i) { - Some(hostaddr) if hostaddr.is_empty() => Host::Tcp(hostaddr.clone()), - _ => host.clone(), - }, - #[cfg(unix)] - Host::Unix(_v) => host.clone(), + // Try to use the value of hostaddr to establish the TCP connection, + // fallback to host if hostaddr is not present. + let addr = match hostaddr { + Some(ipaddr) => Host::Tcp(ipaddr.to_string()), + None => { + if let Some(host) = host { + host.clone() + } else { + // This is unreachable. + return Err(Error::config("both host and hostaddr are empty".into())); + } + } }; - match connect_once(&hostaddr, port, tls, config).await { + match connect_once(&addr, port, tls, config).await { Ok((client, connection)) => return Ok((client, connection)), Err(e) => error = Some(e), } diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index 0ab4a7bab..387c90d7c 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -147,6 +147,58 @@ async fn scram_password_ok() { connect("user=scram_user password=password dbname=postgres").await; } +#[tokio::test] +async fn host_only_ok() { + let _ = tokio_postgres::connect( + "host=localhost port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_only_ok() { + let _ = tokio_postgres::connect( + "hostaddr=127.0.0.1 port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_and_host_ok() { + let _ = tokio_postgres::connect( + "hostaddr=127.0.0.1 host=localhost port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_host_mismatch() { + let _ = tokio_postgres::connect( + "hostaddr=127.0.0.1,127.0.0.2 host=localhost port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .err() + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_host_both_missing() { + let _ = tokio_postgres::connect( + "port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .err() + .unwrap(); +} + #[tokio::test] async fn pipelined_prepare() { let client = connect("user=postgres").await; From e30bff65a35d1240f8b920c49569a40563712e5d Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Sat, 27 Aug 2022 11:55:11 -0700 Subject: [PATCH 211/420] also update postgres --- postgres/src/config.rs | 33 +++++++++++++++++++++++++++++++++ tokio-postgres/src/config.rs | 1 + 2 files changed, 34 insertions(+) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index b541ec846..a754ff91f 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -6,6 +6,7 @@ use crate::connection::Connection; use crate::Client; use log::info; use std::fmt; +use std::net::IpAddr; use std::path::Path; use std::str::FromStr; use std::sync::Arc; @@ -39,6 +40,19 @@ 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. +/// * `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, +/// - or if host specifies an IP address, that value will be used directly. +/// Using `hostaddr` allows the application to avoid a host name look-up, which might be important in applications +/// with time constraints. However, a host name is required for verify-full SSL certificate verification. +/// Specifically: +/// * If `hostaddr` is specified without `host`, the value for `hostaddr` gives the server network address. +/// The connection attempt will fail if the authentication method requires a host name; +/// * If `host` is specified without `hostaddr`, a host name lookup occurs; +/// * If both `host` and `hostaddr` are specified, the value for `hostaddr` gives the server network address. +/// The value for `host` is ignored unless the authentication method requires it, +/// in which case it will be used as the host name. /// * `port` - The port to connect to. Multiple ports can be specified, separated by commas. The number of ports must be /// either 1, in which case it will be used for all hosts, or the same as the number of hosts. Defaults to 5432 if /// omitted or the empty string. @@ -67,6 +81,10 @@ use tokio_postgres::{Error, Socket}; /// ``` /// /// ```not_rust +/// host=host1,host2,host3 port=1234,,5678 hostaddr=127.0.0.1,127.0.0.2,127.0.0.3 user=postgres target_session_attrs=read-write +/// ``` +/// +/// ```not_rust /// host=host1,host2,host3 port=1234,,5678 user=postgres target_session_attrs=read-write /// ``` /// @@ -204,6 +222,7 @@ impl Config { /// /// Multiple hosts can be specified by calling this method multiple times, and each will be tried in order. On Unix /// systems, a host starting with a `/` is interpreted as a path to a directory containing Unix domain sockets. + /// There must be either no hosts, or the same number of hosts as hostaddrs. pub fn host(&mut self, host: &str) -> &mut Config { self.config.host(host); self @@ -214,6 +233,11 @@ impl Config { self.config.get_hosts() } + /// Gets the hostaddrs that have been added to the configuration with `hostaddr`. + pub fn get_hostaddrs(&self) -> &[IpAddr] { + self.config.get_hostaddrs() + } + /// Adds a Unix socket host to the configuration. /// /// Unlike `host`, this method allows non-UTF8 paths. @@ -226,6 +250,15 @@ impl Config { self } + /// Adds a hostaddr to the configuration. + /// + /// Multiple hostaddrs can be specified by calling this method multiple times, and each will be tried in order. + /// There must be either no hostaddrs, or the same number of hostaddrs as hosts. + pub fn hostaddr(&mut self, hostaddr: IpAddr) -> &mut Config { + self.config.hostaddr(hostaddr); + self + } + /// Adds a port to the configuration. /// /// Multiple ports can be specified by calling this method multiple times. There must either be no ports, in which diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 34accdbe8..923da2985 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -302,6 +302,7 @@ impl Config { /// /// Multiple hosts can be specified by calling this method multiple times, and each will be tried in order. On Unix /// systems, a host starting with a `/` is interpreted as a path to a directory containing Unix domain sockets. + /// There must be either no hosts, or the same number of hosts as hostaddrs. pub fn host(&mut self, host: &str) -> &mut Config { #[cfg(unix)] { From 6c49a452feb273430d0091de83961ad65ffb9102 Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Sat, 27 Aug 2022 11:55:47 -0700 Subject: [PATCH 212/420] fmt --- postgres/src/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index a754ff91f..921566b66 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -83,7 +83,7 @@ use tokio_postgres::{Error, Socket}; /// ```not_rust /// host=host1,host2,host3 port=1234,,5678 hostaddr=127.0.0.1,127.0.0.2,127.0.0.3 user=postgres target_session_attrs=read-write /// ``` -/// +/// /// ```not_rust /// host=host1,host2,host3 port=1234,,5678 user=postgres target_session_attrs=read-write /// ``` @@ -236,7 +236,7 @@ impl Config { /// Gets the hostaddrs that have been added to the configuration with `hostaddr`. pub fn get_hostaddrs(&self) -> &[IpAddr] { self.config.get_hostaddrs() - } + } /// Adds a Unix socket host to the configuration. /// From 42fef24973dff5450b294df21e94e665fe4d996d Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Sun, 28 Aug 2022 12:09:53 -0700 Subject: [PATCH 213/420] explicitly handle host being None --- tokio-postgres/src/connect.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index ee1dc1c76..63574516c 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -51,14 +51,17 @@ where .copied() .unwrap_or(5432); - // The value of host is always used as the hostname for TLS validation. - // postgres doesn't support TLS over unix sockets, so the choice for Host::Unix variant here doesn't matter + // The value of host is used as the hostname for TLS validation, + // if it's not present, use the value of hostaddr. let hostname = match host { - Some(Host::Tcp(host)) => host.as_str(), - _ => "", + Some(Host::Tcp(host)) => host.clone(), + // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter Some() + #[cfg(unix)] + Some(Host::Unix(_)) => "".to_string(), + None => hostaddr.map_or("".to_string(), |ipaddr| ipaddr.to_string()), }; let tls = tls - .make_tls_connect(hostname) + .make_tls_connect(&hostname) .map_err(|e| Error::tls(e.into()))?; // Try to use the value of hostaddr to establish the TCP connection, From 9b34d74df143527602a18b1564b554647dbf5eaf Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Sun, 28 Aug 2022 12:18:36 -0700 Subject: [PATCH 214/420] add negative test --- tokio-postgres/src/config.rs | 6 ++++++ tokio-postgres/src/connect.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 923da2985..e5bed8ddf 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -1051,4 +1051,10 @@ mod tests { assert_eq!(1, 1); } + + #[test] + fn test_invalid_hostaddr_parsing() { + let s = "user=pass_user dbname=postgres host=host1 hostaddr=127.0.0 port=26257"; + s.parse::().err().unwrap(); + } } diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 63574516c..888f9cf8a 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -55,7 +55,7 @@ where // if it's not present, use the value of hostaddr. let hostname = match host { Some(Host::Tcp(host)) => host.clone(), - // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter Some() + // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter #[cfg(unix)] Some(Host::Unix(_)) => "".to_string(), None => hostaddr.map_or("".to_string(), |ipaddr| ipaddr.to_string()), From 8ac10ff1de52281592d5bdd75e109d995ca33a2c Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Tue, 30 Aug 2022 22:10:19 -0700 Subject: [PATCH 215/420] move test to runtime --- tokio-postgres/tests/test/main.rs | 52 ---------------------------- tokio-postgres/tests/test/runtime.rs | 52 ++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index 387c90d7c..0ab4a7bab 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -147,58 +147,6 @@ async fn scram_password_ok() { connect("user=scram_user password=password dbname=postgres").await; } -#[tokio::test] -async fn host_only_ok() { - let _ = tokio_postgres::connect( - "host=localhost port=5433 user=pass_user dbname=postgres password=password", - NoTls, - ) - .await - .unwrap(); -} - -#[tokio::test] -async fn hostaddr_only_ok() { - let _ = tokio_postgres::connect( - "hostaddr=127.0.0.1 port=5433 user=pass_user dbname=postgres password=password", - NoTls, - ) - .await - .unwrap(); -} - -#[tokio::test] -async fn hostaddr_and_host_ok() { - let _ = tokio_postgres::connect( - "hostaddr=127.0.0.1 host=localhost port=5433 user=pass_user dbname=postgres password=password", - NoTls, - ) - .await - .unwrap(); -} - -#[tokio::test] -async fn hostaddr_host_mismatch() { - let _ = tokio_postgres::connect( - "hostaddr=127.0.0.1,127.0.0.2 host=localhost port=5433 user=pass_user dbname=postgres password=password", - NoTls, - ) - .await - .err() - .unwrap(); -} - -#[tokio::test] -async fn hostaddr_host_both_missing() { - let _ = tokio_postgres::connect( - "port=5433 user=pass_user dbname=postgres password=password", - NoTls, - ) - .await - .err() - .unwrap(); -} - #[tokio::test] async fn pipelined_prepare() { let client = connect("user=postgres").await; diff --git a/tokio-postgres/tests/test/runtime.rs b/tokio-postgres/tests/test/runtime.rs index 67b4ead8a..86c1f0701 100644 --- a/tokio-postgres/tests/test/runtime.rs +++ b/tokio-postgres/tests/test/runtime.rs @@ -66,6 +66,58 @@ async fn target_session_attrs_err() { .unwrap(); } +#[tokio::test] +async fn host_only_ok() { + let _ = tokio_postgres::connect( + "host=localhost port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_only_ok() { + let _ = tokio_postgres::connect( + "hostaddr=127.0.0.1 port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_and_host_ok() { + let _ = tokio_postgres::connect( + "hostaddr=127.0.0.1 host=localhost port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_host_mismatch() { + let _ = tokio_postgres::connect( + "hostaddr=127.0.0.1,127.0.0.2 host=localhost port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .err() + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_host_both_missing() { + let _ = tokio_postgres::connect( + "port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .err() + .unwrap(); +} + #[tokio::test] async fn cancel_query() { let client = connect("host=localhost port=5433 user=postgres").await; From 3827b2e44279bbb8b869e07cf91c383d2445893d Mon Sep 17 00:00:00 2001 From: Matt Duch Date: Thu, 25 Aug 2022 19:29:09 -0500 Subject: [PATCH 216/420] derive bounds on generics --- postgres-derive-test/src/composites.rs | 10 ++++----- postgres-derive/src/composites.rs | 26 ++++++++++++++++++++++- postgres-derive/src/fromsql.rs | 29 +++++++++++++++++++++++--- postgres-derive/src/tosql.rs | 20 +++++++++++++++--- 4 files changed, 73 insertions(+), 12 deletions(-) diff --git a/postgres-derive-test/src/composites.rs b/postgres-derive-test/src/composites.rs index 667633519..a1b76345f 100644 --- a/postgres-derive-test/src/composites.rs +++ b/postgres-derive-test/src/composites.rs @@ -1,6 +1,6 @@ use crate::{test_type, test_type_asymmetric}; use postgres::{Client, NoTls}; -use postgres_types::{FromSql, FromSqlOwned, ToSql, WrongType}; +use postgres_types::{FromSql, ToSql, WrongType}; use std::error::Error; #[test] @@ -242,9 +242,9 @@ fn raw_ident_field() { #[test] fn generics() { #[derive(FromSql, Debug, PartialEq)] - struct InventoryItem + struct InventoryItem where - U: FromSqlOwned, + U: Clone, { name: String, supplier_id: T, @@ -254,9 +254,9 @@ fn generics() { // doesn't make sense to implement derived FromSql on a type with borrows #[derive(ToSql, Debug, PartialEq)] #[postgres(name = "InventoryItem")] - struct InventoryItemRef<'a, T: 'a + ToSql, U> + struct InventoryItemRef<'a, T: 'a + Clone, U> where - U: 'a + ToSql, + U: 'a + Clone, { name: &'a str, supplier_id: &'a T, diff --git a/postgres-derive/src/composites.rs b/postgres-derive/src/composites.rs index c1e495154..15bfabc13 100644 --- a/postgres-derive/src/composites.rs +++ b/postgres-derive/src/composites.rs @@ -1,4 +1,8 @@ -use syn::{Error, Ident, Type}; +use proc_macro2::Span; +use syn::{ + punctuated::Punctuated, Error, GenericParam, Generics, Ident, Path, PathSegment, Type, + TypeParamBound, +}; use crate::overrides::Overrides; @@ -26,3 +30,23 @@ impl Field { }) } } + +pub(crate) fn append_generic_bound(mut generics: Generics, bound: &TypeParamBound) -> Generics { + for param in &mut generics.params { + if let GenericParam::Type(param) = param { + param.bounds.push(bound.to_owned()) + } + } + generics +} + +pub(crate) fn new_derive_path(last: PathSegment) -> Path { + let mut path = Path { + leading_colon: None, + segments: Punctuated::new(), + }; + path.segments + .push(Ident::new("postgres_types", Span::call_site()).into()); + path.segments.push(last); + path +} diff --git a/postgres-derive/src/fromsql.rs b/postgres-derive/src/fromsql.rs index 415343653..f458c6e3d 100644 --- a/postgres-derive/src/fromsql.rs +++ b/postgres-derive/src/fromsql.rs @@ -2,12 +2,15 @@ use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote}; use std::iter; use syn::{ - Data, DataStruct, DeriveInput, Error, Fields, GenericParam, Generics, Ident, Lifetime, - LifetimeDef, + punctuated::Punctuated, token, AngleBracketedGenericArguments, Data, DataStruct, DeriveInput, + Error, Fields, GenericArgument, GenericParam, Generics, Ident, Lifetime, LifetimeDef, + PathArguments, PathSegment, }; +use syn::{TraitBound, TraitBoundModifier, TypeParamBound}; use crate::accepts; use crate::composites::Field; +use crate::composites::{append_generic_bound, new_derive_path}; use crate::enums::Variant; use crate::overrides::Overrides; @@ -208,9 +211,10 @@ fn composite_body(ident: &Ident, fields: &[Field]) -> TokenStream { } fn build_generics(source: &Generics) -> (Generics, Lifetime) { - let mut out = source.to_owned(); // don't worry about lifetime name collisions, it doesn't make sense to derive FromSql on a struct with a lifetime let lifetime = Lifetime::new("'a", Span::call_site()); + + let mut out = append_generic_bound(source.to_owned(), &new_fromsql_bound(&lifetime)); out.params.insert( 0, GenericParam::Lifetime(LifetimeDef::new(lifetime.to_owned())), @@ -218,3 +222,22 @@ fn build_generics(source: &Generics) -> (Generics, Lifetime) { (out, lifetime) } + +fn new_fromsql_bound(lifetime: &Lifetime) -> TypeParamBound { + let mut path_segment: PathSegment = Ident::new("FromSql", Span::call_site()).into(); + let mut seg_args = Punctuated::new(); + seg_args.push(GenericArgument::Lifetime(lifetime.to_owned())); + path_segment.arguments = PathArguments::AngleBracketed(AngleBracketedGenericArguments { + colon2_token: None, + lt_token: token::Lt::default(), + args: seg_args, + gt_token: token::Gt::default(), + }); + + TypeParamBound::Trait(TraitBound { + lifetimes: None, + modifier: TraitBoundModifier::None, + paren_token: None, + path: new_derive_path(path_segment), + }) +} diff --git a/postgres-derive/src/tosql.rs b/postgres-derive/src/tosql.rs index 299074f8d..e51acc7fd 100644 --- a/postgres-derive/src/tosql.rs +++ b/postgres-derive/src/tosql.rs @@ -1,10 +1,14 @@ -use proc_macro2::TokenStream; +use proc_macro2::{Span, TokenStream}; use quote::quote; use std::iter; -use syn::{Data, DataStruct, DeriveInput, Error, Fields, Ident}; +use syn::{ + Data, DataStruct, DeriveInput, Error, Fields, Ident, TraitBound, TraitBoundModifier, + TypeParamBound, +}; use crate::accepts; use crate::composites::Field; +use crate::composites::{append_generic_bound, new_derive_path}; use crate::enums::Variant; use crate::overrides::Overrides; @@ -82,7 +86,8 @@ pub fn expand_derive_tosql(input: DeriveInput) -> Result { }; let ident = &input.ident; - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + let generics = append_generic_bound(input.generics.to_owned(), &new_tosql_bound()); + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let out = quote! { impl#impl_generics postgres_types::ToSql for #ident#ty_generics #where_clause { fn to_sql(&self, @@ -182,3 +187,12 @@ fn composite_body(fields: &[Field]) -> TokenStream { std::result::Result::Ok(postgres_types::IsNull::No) } } + +fn new_tosql_bound() -> TypeParamBound { + TypeParamBound::Trait(TraitBound { + lifetimes: None, + modifier: TraitBoundModifier::None, + paren_token: None, + path: new_derive_path(Ident::new("ToSql", Span::call_site()).into()), + }) +} From dfe3bc04937627d176c643267dc4a25d93831ccb Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 7 Sep 2022 19:01:27 -0400 Subject: [PATCH 217/420] Release v0.4.3 --- postgres-derive/CHANGELOG.md | 6 ++++++ postgres-derive/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres-derive/CHANGELOG.md b/postgres-derive/CHANGELOG.md index 1cc55bfe8..dde466a97 100644 --- a/postgres-derive/CHANGELOG.md +++ b/postgres-derive/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.4.3 - 2022-09-07 + +### Added + +* Added support for parameterized structs. + ## v0.4.2 - 2022-04-30 ### Added diff --git a/postgres-derive/Cargo.toml b/postgres-derive/Cargo.toml index 324400162..22b50b707 100644 --- a/postgres-derive/Cargo.toml +++ b/postgres-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-derive" -version = "0.4.2" +version = "0.4.3" authors = ["Steven Fackler "] license = "MIT/Apache-2.0" edition = "2018" From e5f7f8e291928152b1dad3319a494ddbb8d507a7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Sep 2022 13:19:27 +0000 Subject: [PATCH 218/420] Update criterion requirement from 0.3 to 0.4 Updates the requirements on [criterion](https://github.com/bheisler/criterion.rs) to permit the latest version. - [Release notes](https://github.com/bheisler/criterion.rs/releases) - [Changelog](https://github.com/bheisler/criterion.rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/bheisler/criterion.rs/compare/0.3.0...0.4.0) --- updated-dependencies: - dependency-name: criterion dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- postgres/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 2ca65941b..bd7c297f3 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -45,5 +45,5 @@ tokio = { version = "1.0", features = ["rt", "time"] } log = "0.4" [dev-dependencies] -criterion = "0.3" +criterion = "0.4" tokio = { version = "1.0", features = ["rt-multi-thread"] } diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 1a9638eff..760105104 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -61,7 +61,7 @@ tokio-util = { version = "0.7", features = ["codec"] } [dev-dependencies] futures-executor = "0.3" -criterion = "0.3" +criterion = "0.4" env_logger = "0.9" tokio = { version = "1.0", features = [ "macros", From 7faeea5acc3c24493b97306f0238712bf7e0b4e9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 21 Nov 2022 15:19:11 -0800 Subject: [PATCH 219/420] Fix clippy/deprecation warnings --- postgres-protocol/src/authentication/mod.rs | 2 +- postgres-types/src/chrono_04.rs | 8 ++++---- postgres-types/src/geo_types_07.rs | 4 ++-- postgres-types/src/lib.rs | 10 +++++----- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/postgres-protocol/src/authentication/mod.rs b/postgres-protocol/src/authentication/mod.rs index 9cfd6034c..71afa4b9b 100644 --- a/postgres-protocol/src/authentication/mod.rs +++ b/postgres-protocol/src/authentication/mod.rs @@ -15,7 +15,7 @@ pub fn md5_hash(username: &[u8], password: &[u8], salt: [u8; 4]) -> String { md5.update(username); let output = md5.finalize_reset(); md5.update(format!("{:x}", output)); - md5.update(&salt); + md5.update(salt); format!("md5{:x}", md5.finalize()) } diff --git a/postgres-types/src/chrono_04.rs b/postgres-types/src/chrono_04.rs index fcd25e6d1..180ee3766 100644 --- a/postgres-types/src/chrono_04.rs +++ b/postgres-types/src/chrono_04.rs @@ -6,7 +6,7 @@ use std::error::Error; use crate::{FromSql, IsNull, ToSql, Type}; fn base() -> NaiveDateTime { - NaiveDate::from_ymd(2000, 1, 1).and_hms(0, 0, 0) + NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap() } impl<'a> FromSql<'a> for NaiveDateTime { @@ -84,7 +84,7 @@ impl<'a> FromSql<'a> for DateTime { raw: &[u8], ) -> Result, Box> { let utc = DateTime::::from_sql(type_, raw)?; - Ok(utc.with_timezone(&FixedOffset::east(0))) + Ok(utc.with_timezone(&FixedOffset::east_opt(0).unwrap())) } accepts!(TIMESTAMPTZ); @@ -133,7 +133,7 @@ impl ToSql for NaiveDate { impl<'a> FromSql<'a> for NaiveTime { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let usec = types::time_from_sql(raw)?; - Ok(NaiveTime::from_hms(0, 0, 0) + Duration::microseconds(usec)) + Ok(NaiveTime::from_hms_opt(0, 0, 0).unwrap() + Duration::microseconds(usec)) } accepts!(TIME); @@ -141,7 +141,7 @@ impl<'a> FromSql<'a> for NaiveTime { impl ToSql for NaiveTime { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { - let delta = self.signed_duration_since(NaiveTime::from_hms(0, 0, 0)); + let delta = self.signed_duration_since(NaiveTime::from_hms_opt(0, 0, 0).unwrap()); let time = match delta.num_microseconds() { Some(time) => time, None => return Err("value too large to transmit".into()), diff --git a/postgres-types/src/geo_types_07.rs b/postgres-types/src/geo_types_07.rs index 7dfb51056..bf7fa5601 100644 --- a/postgres-types/src/geo_types_07.rs +++ b/postgres-types/src/geo_types_07.rs @@ -1,6 +1,6 @@ use bytes::BytesMut; use fallible_iterator::FallibleIterator; -use geo_types_0_7::{Coordinate, LineString, Point, Rect}; +use geo_types_0_7::{Coord, LineString, Point, Rect}; use postgres_protocol::types; use std::error::Error; @@ -52,7 +52,7 @@ impl<'a> FromSql<'a> for LineString { let path = types::path_from_sql(raw)?; let points = path .points() - .map(|p| Ok(Coordinate { x: p.x(), y: p.y() })) + .map(|p| Ok(Coord { x: p.x(), y: p.y() })) .collect()?; Ok(LineString(points)) } diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index f5d841cd1..ca4233f8a 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -938,7 +938,7 @@ impl<'a, T: ToSql> ToSql for &'a [T] { impl<'a> ToSql for &'a [u8] { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { - types::bytea_to_sql(*self, w); + types::bytea_to_sql(self, w); Ok(IsNull::No) } @@ -1011,10 +1011,10 @@ impl ToSql for Vec { impl<'a> ToSql for &'a str { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { match *ty { - ref ty if ty.name() == "ltree" => types::ltree_to_sql(*self, w), - ref ty if ty.name() == "lquery" => types::lquery_to_sql(*self, w), - ref ty if ty.name() == "ltxtquery" => types::ltxtquery_to_sql(*self, w), - _ => types::text_to_sql(*self, w), + ref ty if ty.name() == "ltree" => types::ltree_to_sql(self, w), + ref ty if ty.name() == "lquery" => types::lquery_to_sql(self, w), + ref ty if ty.name() == "ltxtquery" => types::ltxtquery_to_sql(self, w), + _ => types::text_to_sql(self, w), } Ok(IsNull::No) } From 6c18ac09b95a65af45be899f9151928d91ecb48a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 21 Nov 2022 15:20:25 -0800 Subject: [PATCH 220/420] rustfmt --- postgres-types/src/chrono_04.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/postgres-types/src/chrono_04.rs b/postgres-types/src/chrono_04.rs index 180ee3766..0ec92437d 100644 --- a/postgres-types/src/chrono_04.rs +++ b/postgres-types/src/chrono_04.rs @@ -6,7 +6,10 @@ use std::error::Error; use crate::{FromSql, IsNull, ToSql, Type}; fn base() -> NaiveDateTime { - NaiveDate::from_ymd_opt(2000, 1, 1).unwrap().and_hms_opt(0, 0, 0).unwrap() + NaiveDate::from_ymd_opt(2000, 1, 1) + .unwrap() + .and_hms_opt(0, 0, 0) + .unwrap() } impl<'a> FromSql<'a> for NaiveDateTime { From 6557bca87137207adc7aa4ca3c3eaee4f3beffb6 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 21 Nov 2022 15:25:39 -0800 Subject: [PATCH 221/420] more clippy --- postgres-derive-test/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/postgres-derive-test/src/lib.rs b/postgres-derive-test/src/lib.rs index 8bfd147fb..d1478ac4c 100644 --- a/postgres-derive-test/src/lib.rs +++ b/postgres-derive-test/src/lib.rs @@ -16,12 +16,12 @@ where { for &(ref val, ref repr) in checks.iter() { let stmt = conn - .prepare(&*format!("SELECT {}::{}", *repr, sql_type)) + .prepare(&format!("SELECT {}::{}", *repr, sql_type)) .unwrap(); let result = conn.query_one(&stmt, &[]).unwrap().get(0); assert_eq!(val, &result); - let stmt = conn.prepare(&*format!("SELECT $1::{}", sql_type)).unwrap(); + let stmt = conn.prepare(&format!("SELECT $1::{}", sql_type)).unwrap(); let result = conn.query_one(&stmt, &[val]).unwrap().get(0); assert_eq!(val, &result); } @@ -40,12 +40,12 @@ pub fn test_type_asymmetric( { for &(ref val, ref repr) in checks.iter() { let stmt = conn - .prepare(&*format!("SELECT {}::{}", *repr, sql_type)) + .prepare(&format!("SELECT {}::{}", *repr, sql_type)) .unwrap(); let result: F = conn.query_one(&stmt, &[]).unwrap().get(0); assert!(cmp(val, &result)); - let stmt = conn.prepare(&*format!("SELECT $1::{}", sql_type)).unwrap(); + let stmt = conn.prepare(&format!("SELECT $1::{}", sql_type)).unwrap(); let result: F = conn.query_one(&stmt, &[val]).unwrap().get(0); assert!(cmp(val, &result)); } From f48c3b577f3e4515f2d0e88dcf026295194e4295 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 21 Nov 2022 15:26:37 -0800 Subject: [PATCH 222/420] more deprecations --- tokio-postgres/tests/test/types/geo_types_07.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tokio-postgres/tests/test/types/geo_types_07.rs b/tokio-postgres/tests/test/types/geo_types_07.rs index 85ff2553a..43a13f451 100644 --- a/tokio-postgres/tests/test/types/geo_types_07.rs +++ b/tokio-postgres/tests/test/types/geo_types_07.rs @@ -1,5 +1,5 @@ #[cfg(feature = "with-geo-types-0_7")] -use geo_types_07::{Coordinate, LineString, Point, Rect}; +use geo_types_07::{Coord, LineString, Point, Rect}; use crate::types::test_type; @@ -23,8 +23,8 @@ async fn test_box_params() { &[ ( Some(Rect::new( - Coordinate { x: -3.2, y: 1.618 }, - Coordinate { + Coord { x: -3.2, y: 1.618 }, + Coord { x: 160.0, y: 69701.5615, }, @@ -40,9 +40,9 @@ async fn test_box_params() { #[tokio::test] async fn test_path_params() { let points = vec![ - Coordinate { x: 0., y: 0. }, - Coordinate { x: -3.2, y: 1.618 }, - Coordinate { + Coord { x: 0., y: 0. }, + Coord { x: -3.2, y: 1.618 }, + Coord { x: 160.0, y: 69701.5615, }, From b29164d53a7bcc16fed7aceb7cb6cb9a3faf214a Mon Sep 17 00:00:00 2001 From: Joseph Koshakow Date: Mon, 21 Nov 2022 12:15:38 -0500 Subject: [PATCH 223/420] Add idle session timeout error This commit adds the idle session timeout error (57P05). See https://www.postgresql.org/docs/current/errcodes-appendix.html --- tokio-postgres/src/error/sqlstate.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tokio-postgres/src/error/sqlstate.rs b/tokio-postgres/src/error/sqlstate.rs index 71648a948..4eb1ae2d0 100644 --- a/tokio-postgres/src/error/sqlstate.rs +++ b/tokio-postgres/src/error/sqlstate.rs @@ -232,6 +232,7 @@ impl SqlState { Inner::E57P02 => "57P02", Inner::E57P03 => "57P03", Inner::E57P04 => "57P04", + Inner::E57P05 => "57P05", Inner::E58000 => "58000", Inner::E58030 => "58030", Inner::E58P01 => "58P01", @@ -946,6 +947,9 @@ impl SqlState { /// 57P04 pub const DATABASE_DROPPED: SqlState = SqlState(Inner::E57P04); + /// 57P05 + pub const IDLE_SESSION_TIMEOUT: SqlState = SqlState(Inner::E57P05); + /// 58000 pub const SYSTEM_ERROR: SqlState = SqlState(Inner::E58000); @@ -1292,6 +1296,7 @@ enum Inner { E57P02, E57P03, E57P04, + E57P05, E58000, E58030, E58P01, @@ -1498,6 +1503,7 @@ static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ("55006", SqlState::OBJECT_IN_USE), ("42P01", SqlState::UNDEFINED_TABLE), ("25P03", SqlState::IDLE_IN_TRANSACTION_SESSION_TIMEOUT), + ("57P05", SqlState::IDLE_SESSION_TIMEOUT), ("22037", SqlState::NON_UNIQUE_KEYS_IN_A_JSON_OBJECT), ("2203A", SqlState::SQL_JSON_MEMBER_NOT_FOUND), ("P0004", SqlState::ASSERT_FAILURE), From 664345f9ec06920c3129be2f1b7e0dd6c031c8ef Mon Sep 17 00:00:00 2001 From: Joseph Koshakow Date: Mon, 21 Nov 2022 14:50:52 -0500 Subject: [PATCH 224/420] Update PostgreSQL files to most recent version --- codegen/src/errcodes.txt | 4 +- codegen/src/pg_range.dat | 23 +++--- codegen/src/pg_type.dat | 160 +++++++++++++++++++++++++++------------ 3 files changed, 127 insertions(+), 60 deletions(-) diff --git a/codegen/src/errcodes.txt b/codegen/src/errcodes.txt index c79312ed0..62418a051 100644 --- a/codegen/src/errcodes.txt +++ b/codegen/src/errcodes.txt @@ -2,7 +2,7 @@ # errcodes.txt # PostgreSQL error codes # -# Copyright (c) 2003-2020, PostgreSQL Global Development Group +# Copyright (c) 2003-2022, PostgreSQL Global Development Group # # This list serves as the basis for generating source files containing error # codes. It is kept in a common format to make sure all these source files have @@ -222,6 +222,7 @@ Section: Class 22 - Data Exception 2203D E ERRCODE_TOO_MANY_JSON_ARRAY_ELEMENTS too_many_json_array_elements 2203E E ERRCODE_TOO_MANY_JSON_OBJECT_MEMBERS too_many_json_object_members 2203F E ERRCODE_SQL_JSON_SCALAR_REQUIRED sql_json_scalar_required +2203G E ERRCODE_SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE sql_json_item_cannot_be_cast_to_target_type Section: Class 23 - Integrity Constraint Violation @@ -428,6 +429,7 @@ Section: Class 57 - Operator Intervention 57P02 E ERRCODE_CRASH_SHUTDOWN crash_shutdown 57P03 E ERRCODE_CANNOT_CONNECT_NOW cannot_connect_now 57P04 E ERRCODE_DATABASE_DROPPED database_dropped +57P05 E ERRCODE_IDLE_SESSION_TIMEOUT idle_session_timeout Section: Class 58 - System Error (errors external to PostgreSQL itself) diff --git a/codegen/src/pg_range.dat b/codegen/src/pg_range.dat index 479754c24..74d6de0cf 100644 --- a/codegen/src/pg_range.dat +++ b/codegen/src/pg_range.dat @@ -3,7 +3,7 @@ # pg_range.dat # Initial contents of the pg_range system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_range.dat @@ -12,20 +12,23 @@ [ -{ rngtypid => 'int4range', rngsubtype => 'int4', rngsubopc => 'btree/int4_ops', +{ rngtypid => 'int4range', rngsubtype => 'int4', + rngmultitypid => 'int4multirange', rngsubopc => 'btree/int4_ops', rngcanonical => 'int4range_canonical', rngsubdiff => 'int4range_subdiff' }, { rngtypid => 'numrange', rngsubtype => 'numeric', - rngsubopc => 'btree/numeric_ops', rngcanonical => '-', - rngsubdiff => 'numrange_subdiff' }, + rngmultitypid => 'nummultirange', rngsubopc => 'btree/numeric_ops', + rngcanonical => '-', rngsubdiff => 'numrange_subdiff' }, { rngtypid => 'tsrange', rngsubtype => 'timestamp', - rngsubopc => 'btree/timestamp_ops', rngcanonical => '-', - rngsubdiff => 'tsrange_subdiff' }, + rngmultitypid => 'tsmultirange', rngsubopc => 'btree/timestamp_ops', + rngcanonical => '-', rngsubdiff => 'tsrange_subdiff' }, { rngtypid => 'tstzrange', rngsubtype => 'timestamptz', - rngsubopc => 'btree/timestamptz_ops', rngcanonical => '-', - rngsubdiff => 'tstzrange_subdiff' }, -{ rngtypid => 'daterange', rngsubtype => 'date', rngsubopc => 'btree/date_ops', + rngmultitypid => 'tstzmultirange', rngsubopc => 'btree/timestamptz_ops', + rngcanonical => '-', rngsubdiff => 'tstzrange_subdiff' }, +{ rngtypid => 'daterange', rngsubtype => 'date', + rngmultitypid => 'datemultirange', rngsubopc => 'btree/date_ops', rngcanonical => 'daterange_canonical', rngsubdiff => 'daterange_subdiff' }, -{ rngtypid => 'int8range', rngsubtype => 'int8', rngsubopc => 'btree/int8_ops', +{ rngtypid => 'int8range', rngsubtype => 'int8', + rngmultitypid => 'int8multirange', rngsubopc => 'btree/int8_ops', rngcanonical => 'int8range_canonical', rngsubdiff => 'int8range_subdiff' }, ] diff --git a/codegen/src/pg_type.dat b/codegen/src/pg_type.dat index e8be00083..df4587946 100644 --- a/codegen/src/pg_type.dat +++ b/codegen/src/pg_type.dat @@ -3,7 +3,7 @@ # pg_type.dat # Initial contents of the pg_type system catalog. # -# Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group +# Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # # src/include/catalog/pg_type.dat @@ -15,14 +15,10 @@ # For types used in the system catalogs, make sure the values here match # TypInfo[] in bootstrap.c. -# OID symbol macro names for pg_type OIDs are generated by genbki.pl -# according to the following rule, so you don't need to specify them -# here: +# OID symbol macro names for pg_type OIDs are not specified here because +# they are generated by genbki.pl according to the following rule: # foo_bar -> FOO_BAROID # _foo_bar -> FOO_BARARRAYOID -# -# The only oid_symbol entries in this file are for names that don't match -# this rule, and are grandfathered in. # To autogenerate an array type, add 'array_type_oid => 'nnnn' to the element # type, which will instruct genbki.pl to generate a BKI entry for it. @@ -46,15 +42,16 @@ typinput => 'byteain', typoutput => 'byteaout', typreceive => 'bytearecv', typsend => 'byteasend', typalign => 'i', typstorage => 'x' }, { oid => '18', array_type_oid => '1002', descr => 'single character', - typname => 'char', typlen => '1', typbyval => 't', typcategory => 'S', + typname => 'char', typlen => '1', typbyval => 't', typcategory => 'Z', typinput => 'charin', typoutput => 'charout', typreceive => 'charrecv', typsend => 'charsend', typalign => 'c' }, { oid => '19', array_type_oid => '1003', descr => '63-byte type for storing system identifiers', typname => 'name', typlen => 'NAMEDATALEN', typbyval => 'f', - typcategory => 'S', typelem => 'char', typinput => 'namein', - typoutput => 'nameout', typreceive => 'namerecv', typsend => 'namesend', - typalign => 'c', typcollation => 'C' }, + typcategory => 'S', typsubscript => 'raw_array_subscript_handler', + typelem => 'char', typinput => 'namein', typoutput => 'nameout', + typreceive => 'namerecv', typsend => 'namesend', typalign => 'c', + typcollation => 'C' }, { oid => '20', array_type_oid => '1016', descr => '~18 digit integer, 8-byte storage', typname => 'int8', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', @@ -68,7 +65,8 @@ { oid => '22', array_type_oid => '1006', descr => 'array of int2, used in system tables', typname => 'int2vector', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'int2', typinput => 'int2vectorin', typoutput => 'int2vectorout', + typsubscript => 'array_subscript_handler', typelem => 'int2', + typinput => 'int2vectorin', typoutput => 'int2vectorout', typreceive => 'int2vectorrecv', typsend => 'int2vectorsend', typalign => 'i' }, { oid => '23', array_type_oid => '1007', @@ -108,27 +106,28 @@ { oid => '30', array_type_oid => '1013', descr => 'array of oids, used in system tables', typname => 'oidvector', typlen => '-1', typbyval => 'f', typcategory => 'A', - typelem => 'oid', typinput => 'oidvectorin', typoutput => 'oidvectorout', + typsubscript => 'array_subscript_handler', typelem => 'oid', + typinput => 'oidvectorin', typoutput => 'oidvectorout', typreceive => 'oidvectorrecv', typsend => 'oidvectorsend', typalign => 'i' }, # hand-built rowtype entries for bootstrapped catalogs # NB: OIDs assigned here must match the BKI_ROWTYPE_OID declarations -{ oid => '71', +{ oid => '71', array_type_oid => '210', typname => 'pg_type', typlen => '-1', typbyval => 'f', typtype => 'c', typcategory => 'C', typrelid => 'pg_type', typinput => 'record_in', typoutput => 'record_out', typreceive => 'record_recv', typsend => 'record_send', typalign => 'd', typstorage => 'x' }, -{ oid => '75', +{ oid => '75', array_type_oid => '270', typname => 'pg_attribute', typlen => '-1', typbyval => 'f', typtype => 'c', typcategory => 'C', typrelid => 'pg_attribute', typinput => 'record_in', typoutput => 'record_out', typreceive => 'record_recv', typsend => 'record_send', typalign => 'd', typstorage => 'x' }, -{ oid => '81', +{ oid => '81', array_type_oid => '272', typname => 'pg_proc', typlen => '-1', typbyval => 'f', typtype => 'c', typcategory => 'C', typrelid => 'pg_proc', typinput => 'record_in', typoutput => 'record_out', typreceive => 'record_recv', typsend => 'record_send', typalign => 'd', typstorage => 'x' }, -{ oid => '83', +{ oid => '83', array_type_oid => '273', typname => 'pg_class', typlen => '-1', typbyval => 'f', typtype => 'c', typcategory => 'C', typrelid => 'pg_class', typinput => 'record_in', typoutput => 'record_out', typreceive => 'record_recv', @@ -144,35 +143,30 @@ typname => 'xml', typlen => '-1', typbyval => 'f', typcategory => 'U', typinput => 'xml_in', typoutput => 'xml_out', typreceive => 'xml_recv', typsend => 'xml_send', typalign => 'i', typstorage => 'x' }, -{ oid => '194', oid_symbol => 'PGNODETREEOID', - descr => 'string representing an internal node tree', +{ oid => '194', descr => 'string representing an internal node tree', typname => 'pg_node_tree', typlen => '-1', typbyval => 'f', - typcategory => 'S', typinput => 'pg_node_tree_in', + typcategory => 'Z', typinput => 'pg_node_tree_in', typoutput => 'pg_node_tree_out', typreceive => 'pg_node_tree_recv', typsend => 'pg_node_tree_send', typalign => 'i', typstorage => 'x', typcollation => 'default' }, -{ oid => '3361', oid_symbol => 'PGNDISTINCTOID', - descr => 'multivariate ndistinct coefficients', +{ oid => '3361', descr => 'multivariate ndistinct coefficients', typname => 'pg_ndistinct', typlen => '-1', typbyval => 'f', - typcategory => 'S', typinput => 'pg_ndistinct_in', + typcategory => 'Z', typinput => 'pg_ndistinct_in', typoutput => 'pg_ndistinct_out', typreceive => 'pg_ndistinct_recv', typsend => 'pg_ndistinct_send', typalign => 'i', typstorage => 'x', typcollation => 'default' }, -{ oid => '3402', oid_symbol => 'PGDEPENDENCIESOID', - descr => 'multivariate dependencies', +{ oid => '3402', descr => 'multivariate dependencies', typname => 'pg_dependencies', typlen => '-1', typbyval => 'f', - typcategory => 'S', typinput => 'pg_dependencies_in', + typcategory => 'Z', typinput => 'pg_dependencies_in', typoutput => 'pg_dependencies_out', typreceive => 'pg_dependencies_recv', typsend => 'pg_dependencies_send', typalign => 'i', typstorage => 'x', typcollation => 'default' }, -{ oid => '5017', oid_symbol => 'PGMCVLISTOID', - descr => 'multivariate MCV list', - typname => 'pg_mcv_list', typlen => '-1', typbyval => 'f', typcategory => 'S', +{ oid => '5017', descr => 'multivariate MCV list', + typname => 'pg_mcv_list', typlen => '-1', typbyval => 'f', typcategory => 'Z', typinput => 'pg_mcv_list_in', typoutput => 'pg_mcv_list_out', typreceive => 'pg_mcv_list_recv', typsend => 'pg_mcv_list_send', typalign => 'i', typstorage => 'x', typcollation => 'default' }, -{ oid => '32', oid_symbol => 'PGDDLCOMMANDOID', - descr => 'internal type for passing CollectedCommand', +{ oid => '32', descr => 'internal type for passing CollectedCommand', typname => 'pg_ddl_command', typlen => 'SIZEOF_POINTER', typbyval => 't', typtype => 'p', typcategory => 'P', typinput => 'pg_ddl_command_in', typoutput => 'pg_ddl_command_out', typreceive => 'pg_ddl_command_recv', @@ -187,13 +181,15 @@ { oid => '600', array_type_oid => '1017', descr => 'geometric point \'(x, y)\'', typname => 'point', typlen => '16', typbyval => 'f', typcategory => 'G', - typelem => 'float8', typinput => 'point_in', typoutput => 'point_out', - typreceive => 'point_recv', typsend => 'point_send', typalign => 'd' }, + typsubscript => 'raw_array_subscript_handler', typelem => 'float8', + typinput => 'point_in', typoutput => 'point_out', typreceive => 'point_recv', + typsend => 'point_send', typalign => 'd' }, { oid => '601', array_type_oid => '1018', descr => 'geometric line segment \'(pt1,pt2)\'', typname => 'lseg', typlen => '32', typbyval => 'f', typcategory => 'G', - typelem => 'point', typinput => 'lseg_in', typoutput => 'lseg_out', - typreceive => 'lseg_recv', typsend => 'lseg_send', typalign => 'd' }, + typsubscript => 'raw_array_subscript_handler', typelem => 'point', + typinput => 'lseg_in', typoutput => 'lseg_out', typreceive => 'lseg_recv', + typsend => 'lseg_send', typalign => 'd' }, { oid => '602', array_type_oid => '1019', descr => 'geometric path \'(pt1,...)\'', typname => 'path', typlen => '-1', typbyval => 'f', typcategory => 'G', @@ -202,9 +198,9 @@ { oid => '603', array_type_oid => '1020', descr => 'geometric box \'(lower left,upper right)\'', typname => 'box', typlen => '32', typbyval => 'f', typcategory => 'G', - typdelim => ';', typelem => 'point', typinput => 'box_in', - typoutput => 'box_out', typreceive => 'box_recv', typsend => 'box_send', - typalign => 'd' }, + typdelim => ';', typsubscript => 'raw_array_subscript_handler', + typelem => 'point', typinput => 'box_in', typoutput => 'box_out', + typreceive => 'box_recv', typsend => 'box_send', typalign => 'd' }, { oid => '604', array_type_oid => '1027', descr => 'geometric polygon \'(pt1,...)\'', typname => 'polygon', typlen => '-1', typbyval => 'f', typcategory => 'G', @@ -212,8 +208,9 @@ typsend => 'poly_send', typalign => 'd', typstorage => 'x' }, { oid => '628', array_type_oid => '629', descr => 'geometric line', typname => 'line', typlen => '24', typbyval => 'f', typcategory => 'G', - typelem => 'float8', typinput => 'line_in', typoutput => 'line_out', - typreceive => 'line_recv', typsend => 'line_send', typalign => 'd' }, + typsubscript => 'raw_array_subscript_handler', typelem => 'float8', + typinput => 'line_in', typoutput => 'line_out', typreceive => 'line_recv', + typsend => 'line_send', typalign => 'd' }, # OIDS 700 - 799 @@ -237,7 +234,7 @@ typname => 'circle', typlen => '24', typbyval => 'f', typcategory => 'G', typinput => 'circle_in', typoutput => 'circle_out', typreceive => 'circle_recv', typsend => 'circle_send', typalign => 'd' }, -{ oid => '790', oid_symbol => 'CASHOID', array_type_oid => '791', +{ oid => '790', array_type_oid => '791', descr => 'monetary amounts, $d,ddd.cc', typname => 'money', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', typcategory => 'N', typinput => 'cash_in', typoutput => 'cash_out', @@ -409,8 +406,7 @@ typsend => 'uuid_send', typalign => 'c' }, # pg_lsn -{ oid => '3220', oid_symbol => 'LSNOID', array_type_oid => '3221', - descr => 'PostgreSQL LSN datatype', +{ oid => '3220', array_type_oid => '3221', descr => 'PostgreSQL LSN datatype', typname => 'pg_lsn', typlen => '8', typbyval => 'FLOAT8PASSBYVAL', typcategory => 'U', typinput => 'pg_lsn_in', typoutput => 'pg_lsn_out', typreceive => 'pg_lsn_recv', typsend => 'pg_lsn_send', typalign => 'd' }, @@ -447,8 +443,9 @@ # jsonb { oid => '3802', array_type_oid => '3807', descr => 'Binary JSON', typname => 'jsonb', typlen => '-1', typbyval => 'f', typcategory => 'U', - typinput => 'jsonb_in', typoutput => 'jsonb_out', typreceive => 'jsonb_recv', - typsend => 'jsonb_send', typalign => 'i', typstorage => 'x' }, + typsubscript => 'jsonb_subscript_handler', typinput => 'jsonb_in', + typoutput => 'jsonb_out', typreceive => 'jsonb_recv', typsend => 'jsonb_send', + typalign => 'i', typstorage => 'x' }, { oid => '4072', array_type_oid => '4073', descr => 'JSON path', typname => 'jsonpath', typlen => '-1', typbyval => 'f', typcategory => 'U', typinput => 'jsonpath_in', typoutput => 'jsonpath_out', @@ -500,6 +497,46 @@ typreceive => 'range_recv', typsend => 'range_send', typanalyze => 'range_typanalyze', typalign => 'd', typstorage => 'x' }, +# multirange types +{ oid => '4451', array_type_oid => '6150', descr => 'multirange of integers', + typname => 'int4multirange', typlen => '-1', typbyval => 'f', typtype => 'm', + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'i', typstorage => 'x' }, +{ oid => '4532', array_type_oid => '6151', descr => 'multirange of numerics', + typname => 'nummultirange', typlen => '-1', typbyval => 'f', typtype => 'm', + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'i', typstorage => 'x' }, +{ oid => '4533', array_type_oid => '6152', + descr => 'multirange of timestamps without time zone', + typname => 'tsmultirange', typlen => '-1', typbyval => 'f', typtype => 'm', + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'd', typstorage => 'x' }, +{ oid => '4534', array_type_oid => '6153', + descr => 'multirange of timestamps with time zone', + typname => 'tstzmultirange', typlen => '-1', typbyval => 'f', typtype => 'm', + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'd', typstorage => 'x' }, +{ oid => '4535', array_type_oid => '6155', descr => 'multirange of dates', + typname => 'datemultirange', typlen => '-1', typbyval => 'f', typtype => 'm', + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'i', typstorage => 'x' }, +{ oid => '4536', array_type_oid => '6157', descr => 'multirange of bigints', + typname => 'int8multirange', typlen => '-1', typbyval => 'f', typtype => 'm', + typcategory => 'R', typinput => 'multirange_in', + typoutput => 'multirange_out', typreceive => 'multirange_recv', + typsend => 'multirange_send', typanalyze => 'multirange_typanalyze', + typalign => 'd', typstorage => 'x' }, + # pseudo-types # types with typtype='p' represent various special cases in the type system. # These cannot be used to define table columns, but are valid as function @@ -517,8 +554,9 @@ # Arrays of records have typcategory P, so they can't be autogenerated. { oid => '2287', typname => '_record', typlen => '-1', typbyval => 'f', typtype => 'p', - typcategory => 'P', typelem => 'record', typinput => 'array_in', - typoutput => 'array_out', typreceive => 'array_recv', typsend => 'array_send', + typcategory => 'P', typsubscript => 'array_subscript_handler', + typelem => 'record', typinput => 'array_in', typoutput => 'array_out', + typreceive => 'array_recv', typsend => 'array_send', typanalyze => 'array_typanalyze', typalign => 'd', typstorage => 'x' }, { oid => '2275', array_type_oid => '1263', descr => 'C-style string', typname => 'cstring', typlen => '-2', typbyval => 'f', typtype => 'p', @@ -542,7 +580,7 @@ typname => 'trigger', typlen => '4', typbyval => 't', typtype => 'p', typcategory => 'P', typinput => 'trigger_in', typoutput => 'trigger_out', typreceive => '-', typsend => '-', typalign => 'i' }, -{ oid => '3838', oid_symbol => 'EVTTRIGGEROID', +{ oid => '3838', descr => 'pseudo-type for the result of an event trigger function', typname => 'event_trigger', typlen => '4', typbyval => 't', typtype => 'p', typcategory => 'P', typinput => 'event_trigger_in', @@ -629,5 +667,29 @@ typtype => 'p', typcategory => 'P', typinput => 'anycompatiblerange_in', typoutput => 'anycompatiblerange_out', typreceive => '-', typsend => '-', typalign => 'd', typstorage => 'x' }, - +{ oid => '4537', + descr => 'pseudo-type representing a polymorphic base type that is a multirange', + typname => 'anymultirange', typlen => '-1', typbyval => 'f', typtype => 'p', + typcategory => 'P', typinput => 'anymultirange_in', + typoutput => 'anymultirange_out', typreceive => '-', typsend => '-', + typalign => 'd', typstorage => 'x' }, +{ oid => '4538', + descr => 'pseudo-type representing a multirange over a polymorphic common type', + typname => 'anycompatiblemultirange', typlen => '-1', typbyval => 'f', + typtype => 'p', typcategory => 'P', typinput => 'anycompatiblemultirange_in', + typoutput => 'anycompatiblemultirange_out', typreceive => '-', typsend => '-', + typalign => 'd', typstorage => 'x' }, +{ oid => '4600', descr => 'BRIN bloom summary', + typname => 'pg_brin_bloom_summary', typlen => '-1', typbyval => 'f', + typcategory => 'Z', typinput => 'brin_bloom_summary_in', + typoutput => 'brin_bloom_summary_out', + typreceive => 'brin_bloom_summary_recv', typsend => 'brin_bloom_summary_send', + typalign => 'i', typstorage => 'x', typcollation => 'default' }, +{ oid => '4601', descr => 'BRIN minmax-multi summary', + typname => 'pg_brin_minmax_multi_summary', typlen => '-1', typbyval => 'f', + typcategory => 'Z', typinput => 'brin_minmax_multi_summary_in', + typoutput => 'brin_minmax_multi_summary_out', + typreceive => 'brin_minmax_multi_summary_recv', + typsend => 'brin_minmax_multi_summary_send', typalign => 'i', + typstorage => 'x', typcollation => 'default' }, ] From f413e66b14f9b4574b69005a4671441ea10b2e6e Mon Sep 17 00:00:00 2001 From: Joseph Koshakow Date: Mon, 21 Nov 2022 15:24:21 -0500 Subject: [PATCH 225/420] Add support for multiranges --- codegen/src/type_gen.rs | 15 +- postgres-types/src/type_gen.rs | 840 +++++++++++++++++++++------ tokio-postgres/src/error/sqlstate.rs | 572 +++++++++--------- 3 files changed, 971 insertions(+), 456 deletions(-) diff --git a/codegen/src/type_gen.rs b/codegen/src/type_gen.rs index 7e92e062a..249c5530a 100644 --- a/codegen/src/type_gen.rs +++ b/codegen/src/type_gen.rs @@ -185,6 +185,15 @@ fn parse_types() -> BTreeMap { ) }) .collect::>(); + let multi_range_elements = raw_ranges + .iter() + .map(|m| { + ( + oids_by_name[&*m["rngmultitypid"]], + oids_by_name[&*m["rngsubtype"]], + ) + }) + .collect::>(); let range_vector_re = Regex::new("(range|vector)$").unwrap(); let array_re = Regex::new("^_(.*)").unwrap(); @@ -209,7 +218,11 @@ fn parse_types() -> BTreeMap { } let element = match &*kind { - "R" => range_elements[&oid], + "R" => match &*raw_type["typtype"] { + "r" => range_elements[&oid], + "m" => multi_range_elements[&oid], + typtype => panic!("invalid range typtype {}", typtype), + } "A" => oids_by_name[&raw_type["typelem"]], _ => 0, }; diff --git a/postgres-types/src/type_gen.rs b/postgres-types/src/type_gen.rs index 85978096a..901fb46e0 100644 --- a/postgres-types/src/type_gen.rs +++ b/postgres-types/src/type_gen.rs @@ -1,7 +1,7 @@ // Autogenerated file - DO NOT EDIT use std::sync::Arc; -use crate::{Kind, Oid, Type}; +use crate::{Type, Oid, Kind}; #[derive(PartialEq, Eq, Debug, Hash)] pub struct Other { @@ -174,6 +174,16 @@ pub enum Inner { RegroleArray, Regcollation, RegcollationArray, + Int4multiRange, + NummultiRange, + TsmultiRange, + TstzmultiRange, + DatemultiRange, + Int8multiRange, + AnymultiRange, + AnycompatiblemultiRange, + PgBrinBloomSummary, + PgBrinMinmaxMultiSummary, PgMcvList, PgSnapshot, PgSnapshotArray, @@ -182,6 +192,12 @@ pub enum Inner { Anycompatiblearray, Anycompatiblenonarray, AnycompatibleRange, + Int4multiRangeArray, + NummultiRangeArray, + TsmultiRangeArray, + TstzmultiRangeArray, + DatemultiRangeArray, + Int8multiRangeArray, Other(Arc), } @@ -349,6 +365,16 @@ impl Inner { 4097 => Some(Inner::RegroleArray), 4191 => Some(Inner::Regcollation), 4192 => Some(Inner::RegcollationArray), + 4451 => Some(Inner::Int4multiRange), + 4532 => Some(Inner::NummultiRange), + 4533 => Some(Inner::TsmultiRange), + 4534 => Some(Inner::TstzmultiRange), + 4535 => Some(Inner::DatemultiRange), + 4536 => Some(Inner::Int8multiRange), + 4537 => Some(Inner::AnymultiRange), + 4538 => Some(Inner::AnycompatiblemultiRange), + 4600 => Some(Inner::PgBrinBloomSummary), + 4601 => Some(Inner::PgBrinMinmaxMultiSummary), 5017 => Some(Inner::PgMcvList), 5038 => Some(Inner::PgSnapshot), 5039 => Some(Inner::PgSnapshotArray), @@ -357,6 +383,12 @@ impl Inner { 5078 => Some(Inner::Anycompatiblearray), 5079 => Some(Inner::Anycompatiblenonarray), 5080 => Some(Inner::AnycompatibleRange), + 6150 => Some(Inner::Int4multiRangeArray), + 6151 => Some(Inner::NummultiRangeArray), + 6152 => Some(Inner::TsmultiRangeArray), + 6153 => Some(Inner::TstzmultiRangeArray), + 6155 => Some(Inner::DatemultiRangeArray), + 6157 => Some(Inner::Int8multiRangeArray), _ => None, } } @@ -524,6 +556,16 @@ impl Inner { Inner::RegroleArray => 4097, Inner::Regcollation => 4191, Inner::RegcollationArray => 4192, + Inner::Int4multiRange => 4451, + Inner::NummultiRange => 4532, + Inner::TsmultiRange => 4533, + Inner::TstzmultiRange => 4534, + Inner::DatemultiRange => 4535, + Inner::Int8multiRange => 4536, + Inner::AnymultiRange => 4537, + Inner::AnycompatiblemultiRange => 4538, + Inner::PgBrinBloomSummary => 4600, + Inner::PgBrinMinmaxMultiSummary => 4601, Inner::PgMcvList => 5017, Inner::PgSnapshot => 5038, Inner::PgSnapshotArray => 5039, @@ -532,181 +574,573 @@ impl Inner { Inner::Anycompatiblearray => 5078, Inner::Anycompatiblenonarray => 5079, Inner::AnycompatibleRange => 5080, + Inner::Int4multiRangeArray => 6150, + Inner::NummultiRangeArray => 6151, + Inner::TsmultiRangeArray => 6152, + Inner::TstzmultiRangeArray => 6153, + Inner::DatemultiRangeArray => 6155, + Inner::Int8multiRangeArray => 6157, Inner::Other(ref u) => u.oid, } } pub fn kind(&self) -> &Kind { match *self { - Inner::Bool => &Kind::Simple, - Inner::Bytea => &Kind::Simple, - Inner::Char => &Kind::Simple, - Inner::Name => &Kind::Simple, - Inner::Int8 => &Kind::Simple, - Inner::Int2 => &Kind::Simple, - Inner::Int2Vector => &Kind::Array(Type(Inner::Int2)), - Inner::Int4 => &Kind::Simple, - Inner::Regproc => &Kind::Simple, - Inner::Text => &Kind::Simple, - Inner::Oid => &Kind::Simple, - Inner::Tid => &Kind::Simple, - Inner::Xid => &Kind::Simple, - Inner::Cid => &Kind::Simple, - Inner::OidVector => &Kind::Array(Type(Inner::Oid)), - Inner::PgDdlCommand => &Kind::Pseudo, - Inner::Json => &Kind::Simple, - Inner::Xml => &Kind::Simple, - Inner::XmlArray => &Kind::Array(Type(Inner::Xml)), - Inner::PgNodeTree => &Kind::Simple, - Inner::JsonArray => &Kind::Array(Type(Inner::Json)), - Inner::TableAmHandler => &Kind::Pseudo, - Inner::Xid8Array => &Kind::Array(Type(Inner::Xid8)), - Inner::IndexAmHandler => &Kind::Pseudo, - Inner::Point => &Kind::Simple, - Inner::Lseg => &Kind::Simple, - Inner::Path => &Kind::Simple, - Inner::Box => &Kind::Simple, - Inner::Polygon => &Kind::Simple, - Inner::Line => &Kind::Simple, - Inner::LineArray => &Kind::Array(Type(Inner::Line)), - Inner::Cidr => &Kind::Simple, - Inner::CidrArray => &Kind::Array(Type(Inner::Cidr)), - Inner::Float4 => &Kind::Simple, - Inner::Float8 => &Kind::Simple, - Inner::Unknown => &Kind::Simple, - Inner::Circle => &Kind::Simple, - Inner::CircleArray => &Kind::Array(Type(Inner::Circle)), - Inner::Macaddr8 => &Kind::Simple, - Inner::Macaddr8Array => &Kind::Array(Type(Inner::Macaddr8)), - Inner::Money => &Kind::Simple, - Inner::MoneyArray => &Kind::Array(Type(Inner::Money)), - Inner::Macaddr => &Kind::Simple, - Inner::Inet => &Kind::Simple, - Inner::BoolArray => &Kind::Array(Type(Inner::Bool)), - Inner::ByteaArray => &Kind::Array(Type(Inner::Bytea)), - Inner::CharArray => &Kind::Array(Type(Inner::Char)), - Inner::NameArray => &Kind::Array(Type(Inner::Name)), - Inner::Int2Array => &Kind::Array(Type(Inner::Int2)), - Inner::Int2VectorArray => &Kind::Array(Type(Inner::Int2Vector)), - Inner::Int4Array => &Kind::Array(Type(Inner::Int4)), - Inner::RegprocArray => &Kind::Array(Type(Inner::Regproc)), - Inner::TextArray => &Kind::Array(Type(Inner::Text)), - Inner::TidArray => &Kind::Array(Type(Inner::Tid)), - Inner::XidArray => &Kind::Array(Type(Inner::Xid)), - Inner::CidArray => &Kind::Array(Type(Inner::Cid)), - Inner::OidVectorArray => &Kind::Array(Type(Inner::OidVector)), - Inner::BpcharArray => &Kind::Array(Type(Inner::Bpchar)), - Inner::VarcharArray => &Kind::Array(Type(Inner::Varchar)), - Inner::Int8Array => &Kind::Array(Type(Inner::Int8)), - Inner::PointArray => &Kind::Array(Type(Inner::Point)), - Inner::LsegArray => &Kind::Array(Type(Inner::Lseg)), - Inner::PathArray => &Kind::Array(Type(Inner::Path)), - Inner::BoxArray => &Kind::Array(Type(Inner::Box)), - Inner::Float4Array => &Kind::Array(Type(Inner::Float4)), - Inner::Float8Array => &Kind::Array(Type(Inner::Float8)), - Inner::PolygonArray => &Kind::Array(Type(Inner::Polygon)), - Inner::OidArray => &Kind::Array(Type(Inner::Oid)), - Inner::Aclitem => &Kind::Simple, - Inner::AclitemArray => &Kind::Array(Type(Inner::Aclitem)), - Inner::MacaddrArray => &Kind::Array(Type(Inner::Macaddr)), - Inner::InetArray => &Kind::Array(Type(Inner::Inet)), - Inner::Bpchar => &Kind::Simple, - Inner::Varchar => &Kind::Simple, - Inner::Date => &Kind::Simple, - Inner::Time => &Kind::Simple, - Inner::Timestamp => &Kind::Simple, - Inner::TimestampArray => &Kind::Array(Type(Inner::Timestamp)), - Inner::DateArray => &Kind::Array(Type(Inner::Date)), - Inner::TimeArray => &Kind::Array(Type(Inner::Time)), - Inner::Timestamptz => &Kind::Simple, - Inner::TimestamptzArray => &Kind::Array(Type(Inner::Timestamptz)), - Inner::Interval => &Kind::Simple, - Inner::IntervalArray => &Kind::Array(Type(Inner::Interval)), - Inner::NumericArray => &Kind::Array(Type(Inner::Numeric)), - Inner::CstringArray => &Kind::Array(Type(Inner::Cstring)), - Inner::Timetz => &Kind::Simple, - Inner::TimetzArray => &Kind::Array(Type(Inner::Timetz)), - Inner::Bit => &Kind::Simple, - Inner::BitArray => &Kind::Array(Type(Inner::Bit)), - Inner::Varbit => &Kind::Simple, - Inner::VarbitArray => &Kind::Array(Type(Inner::Varbit)), - Inner::Numeric => &Kind::Simple, - Inner::Refcursor => &Kind::Simple, - Inner::RefcursorArray => &Kind::Array(Type(Inner::Refcursor)), - Inner::Regprocedure => &Kind::Simple, - Inner::Regoper => &Kind::Simple, - Inner::Regoperator => &Kind::Simple, - Inner::Regclass => &Kind::Simple, - Inner::Regtype => &Kind::Simple, - Inner::RegprocedureArray => &Kind::Array(Type(Inner::Regprocedure)), - Inner::RegoperArray => &Kind::Array(Type(Inner::Regoper)), - Inner::RegoperatorArray => &Kind::Array(Type(Inner::Regoperator)), - Inner::RegclassArray => &Kind::Array(Type(Inner::Regclass)), - Inner::RegtypeArray => &Kind::Array(Type(Inner::Regtype)), - Inner::Record => &Kind::Pseudo, - Inner::Cstring => &Kind::Pseudo, - Inner::Any => &Kind::Pseudo, - Inner::Anyarray => &Kind::Pseudo, - Inner::Void => &Kind::Pseudo, - Inner::Trigger => &Kind::Pseudo, - Inner::LanguageHandler => &Kind::Pseudo, - Inner::Internal => &Kind::Pseudo, - Inner::Anyelement => &Kind::Pseudo, - Inner::RecordArray => &Kind::Pseudo, - Inner::Anynonarray => &Kind::Pseudo, - Inner::TxidSnapshotArray => &Kind::Array(Type(Inner::TxidSnapshot)), - Inner::Uuid => &Kind::Simple, - Inner::UuidArray => &Kind::Array(Type(Inner::Uuid)), - Inner::TxidSnapshot => &Kind::Simple, - Inner::FdwHandler => &Kind::Pseudo, - Inner::PgLsn => &Kind::Simple, - Inner::PgLsnArray => &Kind::Array(Type(Inner::PgLsn)), - Inner::TsmHandler => &Kind::Pseudo, - Inner::PgNdistinct => &Kind::Simple, - Inner::PgDependencies => &Kind::Simple, - Inner::Anyenum => &Kind::Pseudo, - Inner::TsVector => &Kind::Simple, - Inner::Tsquery => &Kind::Simple, - Inner::GtsVector => &Kind::Simple, - Inner::TsVectorArray => &Kind::Array(Type(Inner::TsVector)), - Inner::GtsVectorArray => &Kind::Array(Type(Inner::GtsVector)), - Inner::TsqueryArray => &Kind::Array(Type(Inner::Tsquery)), - Inner::Regconfig => &Kind::Simple, - Inner::RegconfigArray => &Kind::Array(Type(Inner::Regconfig)), - Inner::Regdictionary => &Kind::Simple, - Inner::RegdictionaryArray => &Kind::Array(Type(Inner::Regdictionary)), - Inner::Jsonb => &Kind::Simple, - Inner::JsonbArray => &Kind::Array(Type(Inner::Jsonb)), - Inner::AnyRange => &Kind::Pseudo, - Inner::EventTrigger => &Kind::Pseudo, - Inner::Int4Range => &Kind::Range(Type(Inner::Int4)), - Inner::Int4RangeArray => &Kind::Array(Type(Inner::Int4Range)), - Inner::NumRange => &Kind::Range(Type(Inner::Numeric)), - Inner::NumRangeArray => &Kind::Array(Type(Inner::NumRange)), - Inner::TsRange => &Kind::Range(Type(Inner::Timestamp)), - Inner::TsRangeArray => &Kind::Array(Type(Inner::TsRange)), - Inner::TstzRange => &Kind::Range(Type(Inner::Timestamptz)), - Inner::TstzRangeArray => &Kind::Array(Type(Inner::TstzRange)), - Inner::DateRange => &Kind::Range(Type(Inner::Date)), - Inner::DateRangeArray => &Kind::Array(Type(Inner::DateRange)), - Inner::Int8Range => &Kind::Range(Type(Inner::Int8)), - Inner::Int8RangeArray => &Kind::Array(Type(Inner::Int8Range)), - Inner::Jsonpath => &Kind::Simple, - Inner::JsonpathArray => &Kind::Array(Type(Inner::Jsonpath)), - Inner::Regnamespace => &Kind::Simple, - Inner::RegnamespaceArray => &Kind::Array(Type(Inner::Regnamespace)), - Inner::Regrole => &Kind::Simple, - Inner::RegroleArray => &Kind::Array(Type(Inner::Regrole)), - Inner::Regcollation => &Kind::Simple, - Inner::RegcollationArray => &Kind::Array(Type(Inner::Regcollation)), - Inner::PgMcvList => &Kind::Simple, - Inner::PgSnapshot => &Kind::Simple, - Inner::PgSnapshotArray => &Kind::Array(Type(Inner::PgSnapshot)), - Inner::Xid8 => &Kind::Simple, - Inner::Anycompatible => &Kind::Pseudo, - Inner::Anycompatiblearray => &Kind::Pseudo, - Inner::Anycompatiblenonarray => &Kind::Pseudo, - Inner::AnycompatibleRange => &Kind::Pseudo, + Inner::Bool => { + &Kind::Simple + } + Inner::Bytea => { + &Kind::Simple + } + Inner::Char => { + &Kind::Simple + } + Inner::Name => { + &Kind::Simple + } + Inner::Int8 => { + &Kind::Simple + } + Inner::Int2 => { + &Kind::Simple + } + Inner::Int2Vector => { + &Kind::Array(Type(Inner::Int2)) + } + Inner::Int4 => { + &Kind::Simple + } + Inner::Regproc => { + &Kind::Simple + } + Inner::Text => { + &Kind::Simple + } + Inner::Oid => { + &Kind::Simple + } + Inner::Tid => { + &Kind::Simple + } + Inner::Xid => { + &Kind::Simple + } + Inner::Cid => { + &Kind::Simple + } + Inner::OidVector => { + &Kind::Array(Type(Inner::Oid)) + } + Inner::PgDdlCommand => { + &Kind::Pseudo + } + Inner::Json => { + &Kind::Simple + } + Inner::Xml => { + &Kind::Simple + } + Inner::XmlArray => { + &Kind::Array(Type(Inner::Xml)) + } + Inner::PgNodeTree => { + &Kind::Simple + } + Inner::JsonArray => { + &Kind::Array(Type(Inner::Json)) + } + Inner::TableAmHandler => { + &Kind::Pseudo + } + Inner::Xid8Array => { + &Kind::Array(Type(Inner::Xid8)) + } + Inner::IndexAmHandler => { + &Kind::Pseudo + } + Inner::Point => { + &Kind::Simple + } + Inner::Lseg => { + &Kind::Simple + } + Inner::Path => { + &Kind::Simple + } + Inner::Box => { + &Kind::Simple + } + Inner::Polygon => { + &Kind::Simple + } + Inner::Line => { + &Kind::Simple + } + Inner::LineArray => { + &Kind::Array(Type(Inner::Line)) + } + Inner::Cidr => { + &Kind::Simple + } + Inner::CidrArray => { + &Kind::Array(Type(Inner::Cidr)) + } + Inner::Float4 => { + &Kind::Simple + } + Inner::Float8 => { + &Kind::Simple + } + Inner::Unknown => { + &Kind::Simple + } + Inner::Circle => { + &Kind::Simple + } + Inner::CircleArray => { + &Kind::Array(Type(Inner::Circle)) + } + Inner::Macaddr8 => { + &Kind::Simple + } + Inner::Macaddr8Array => { + &Kind::Array(Type(Inner::Macaddr8)) + } + Inner::Money => { + &Kind::Simple + } + Inner::MoneyArray => { + &Kind::Array(Type(Inner::Money)) + } + Inner::Macaddr => { + &Kind::Simple + } + Inner::Inet => { + &Kind::Simple + } + Inner::BoolArray => { + &Kind::Array(Type(Inner::Bool)) + } + Inner::ByteaArray => { + &Kind::Array(Type(Inner::Bytea)) + } + Inner::CharArray => { + &Kind::Array(Type(Inner::Char)) + } + Inner::NameArray => { + &Kind::Array(Type(Inner::Name)) + } + Inner::Int2Array => { + &Kind::Array(Type(Inner::Int2)) + } + Inner::Int2VectorArray => { + &Kind::Array(Type(Inner::Int2Vector)) + } + Inner::Int4Array => { + &Kind::Array(Type(Inner::Int4)) + } + Inner::RegprocArray => { + &Kind::Array(Type(Inner::Regproc)) + } + Inner::TextArray => { + &Kind::Array(Type(Inner::Text)) + } + Inner::TidArray => { + &Kind::Array(Type(Inner::Tid)) + } + Inner::XidArray => { + &Kind::Array(Type(Inner::Xid)) + } + Inner::CidArray => { + &Kind::Array(Type(Inner::Cid)) + } + Inner::OidVectorArray => { + &Kind::Array(Type(Inner::OidVector)) + } + Inner::BpcharArray => { + &Kind::Array(Type(Inner::Bpchar)) + } + Inner::VarcharArray => { + &Kind::Array(Type(Inner::Varchar)) + } + Inner::Int8Array => { + &Kind::Array(Type(Inner::Int8)) + } + Inner::PointArray => { + &Kind::Array(Type(Inner::Point)) + } + Inner::LsegArray => { + &Kind::Array(Type(Inner::Lseg)) + } + Inner::PathArray => { + &Kind::Array(Type(Inner::Path)) + } + Inner::BoxArray => { + &Kind::Array(Type(Inner::Box)) + } + Inner::Float4Array => { + &Kind::Array(Type(Inner::Float4)) + } + Inner::Float8Array => { + &Kind::Array(Type(Inner::Float8)) + } + Inner::PolygonArray => { + &Kind::Array(Type(Inner::Polygon)) + } + Inner::OidArray => { + &Kind::Array(Type(Inner::Oid)) + } + Inner::Aclitem => { + &Kind::Simple + } + Inner::AclitemArray => { + &Kind::Array(Type(Inner::Aclitem)) + } + Inner::MacaddrArray => { + &Kind::Array(Type(Inner::Macaddr)) + } + Inner::InetArray => { + &Kind::Array(Type(Inner::Inet)) + } + Inner::Bpchar => { + &Kind::Simple + } + Inner::Varchar => { + &Kind::Simple + } + Inner::Date => { + &Kind::Simple + } + Inner::Time => { + &Kind::Simple + } + Inner::Timestamp => { + &Kind::Simple + } + Inner::TimestampArray => { + &Kind::Array(Type(Inner::Timestamp)) + } + Inner::DateArray => { + &Kind::Array(Type(Inner::Date)) + } + Inner::TimeArray => { + &Kind::Array(Type(Inner::Time)) + } + Inner::Timestamptz => { + &Kind::Simple + } + Inner::TimestamptzArray => { + &Kind::Array(Type(Inner::Timestamptz)) + } + Inner::Interval => { + &Kind::Simple + } + Inner::IntervalArray => { + &Kind::Array(Type(Inner::Interval)) + } + Inner::NumericArray => { + &Kind::Array(Type(Inner::Numeric)) + } + Inner::CstringArray => { + &Kind::Array(Type(Inner::Cstring)) + } + Inner::Timetz => { + &Kind::Simple + } + Inner::TimetzArray => { + &Kind::Array(Type(Inner::Timetz)) + } + Inner::Bit => { + &Kind::Simple + } + Inner::BitArray => { + &Kind::Array(Type(Inner::Bit)) + } + Inner::Varbit => { + &Kind::Simple + } + Inner::VarbitArray => { + &Kind::Array(Type(Inner::Varbit)) + } + Inner::Numeric => { + &Kind::Simple + } + Inner::Refcursor => { + &Kind::Simple + } + Inner::RefcursorArray => { + &Kind::Array(Type(Inner::Refcursor)) + } + Inner::Regprocedure => { + &Kind::Simple + } + Inner::Regoper => { + &Kind::Simple + } + Inner::Regoperator => { + &Kind::Simple + } + Inner::Regclass => { + &Kind::Simple + } + Inner::Regtype => { + &Kind::Simple + } + Inner::RegprocedureArray => { + &Kind::Array(Type(Inner::Regprocedure)) + } + Inner::RegoperArray => { + &Kind::Array(Type(Inner::Regoper)) + } + Inner::RegoperatorArray => { + &Kind::Array(Type(Inner::Regoperator)) + } + Inner::RegclassArray => { + &Kind::Array(Type(Inner::Regclass)) + } + Inner::RegtypeArray => { + &Kind::Array(Type(Inner::Regtype)) + } + Inner::Record => { + &Kind::Pseudo + } + Inner::Cstring => { + &Kind::Pseudo + } + Inner::Any => { + &Kind::Pseudo + } + Inner::Anyarray => { + &Kind::Pseudo + } + Inner::Void => { + &Kind::Pseudo + } + Inner::Trigger => { + &Kind::Pseudo + } + Inner::LanguageHandler => { + &Kind::Pseudo + } + Inner::Internal => { + &Kind::Pseudo + } + Inner::Anyelement => { + &Kind::Pseudo + } + Inner::RecordArray => { + &Kind::Pseudo + } + Inner::Anynonarray => { + &Kind::Pseudo + } + Inner::TxidSnapshotArray => { + &Kind::Array(Type(Inner::TxidSnapshot)) + } + Inner::Uuid => { + &Kind::Simple + } + Inner::UuidArray => { + &Kind::Array(Type(Inner::Uuid)) + } + Inner::TxidSnapshot => { + &Kind::Simple + } + Inner::FdwHandler => { + &Kind::Pseudo + } + Inner::PgLsn => { + &Kind::Simple + } + Inner::PgLsnArray => { + &Kind::Array(Type(Inner::PgLsn)) + } + Inner::TsmHandler => { + &Kind::Pseudo + } + Inner::PgNdistinct => { + &Kind::Simple + } + Inner::PgDependencies => { + &Kind::Simple + } + Inner::Anyenum => { + &Kind::Pseudo + } + Inner::TsVector => { + &Kind::Simple + } + Inner::Tsquery => { + &Kind::Simple + } + Inner::GtsVector => { + &Kind::Simple + } + Inner::TsVectorArray => { + &Kind::Array(Type(Inner::TsVector)) + } + Inner::GtsVectorArray => { + &Kind::Array(Type(Inner::GtsVector)) + } + Inner::TsqueryArray => { + &Kind::Array(Type(Inner::Tsquery)) + } + Inner::Regconfig => { + &Kind::Simple + } + Inner::RegconfigArray => { + &Kind::Array(Type(Inner::Regconfig)) + } + Inner::Regdictionary => { + &Kind::Simple + } + Inner::RegdictionaryArray => { + &Kind::Array(Type(Inner::Regdictionary)) + } + Inner::Jsonb => { + &Kind::Simple + } + Inner::JsonbArray => { + &Kind::Array(Type(Inner::Jsonb)) + } + Inner::AnyRange => { + &Kind::Pseudo + } + Inner::EventTrigger => { + &Kind::Pseudo + } + Inner::Int4Range => { + &Kind::Range(Type(Inner::Int4)) + } + Inner::Int4RangeArray => { + &Kind::Array(Type(Inner::Int4Range)) + } + Inner::NumRange => { + &Kind::Range(Type(Inner::Numeric)) + } + Inner::NumRangeArray => { + &Kind::Array(Type(Inner::NumRange)) + } + Inner::TsRange => { + &Kind::Range(Type(Inner::Timestamp)) + } + Inner::TsRangeArray => { + &Kind::Array(Type(Inner::TsRange)) + } + Inner::TstzRange => { + &Kind::Range(Type(Inner::Timestamptz)) + } + Inner::TstzRangeArray => { + &Kind::Array(Type(Inner::TstzRange)) + } + Inner::DateRange => { + &Kind::Range(Type(Inner::Date)) + } + Inner::DateRangeArray => { + &Kind::Array(Type(Inner::DateRange)) + } + Inner::Int8Range => { + &Kind::Range(Type(Inner::Int8)) + } + Inner::Int8RangeArray => { + &Kind::Array(Type(Inner::Int8Range)) + } + Inner::Jsonpath => { + &Kind::Simple + } + Inner::JsonpathArray => { + &Kind::Array(Type(Inner::Jsonpath)) + } + Inner::Regnamespace => { + &Kind::Simple + } + Inner::RegnamespaceArray => { + &Kind::Array(Type(Inner::Regnamespace)) + } + Inner::Regrole => { + &Kind::Simple + } + Inner::RegroleArray => { + &Kind::Array(Type(Inner::Regrole)) + } + Inner::Regcollation => { + &Kind::Simple + } + Inner::RegcollationArray => { + &Kind::Array(Type(Inner::Regcollation)) + } + Inner::Int4multiRange => { + &Kind::Range(Type(Inner::Int4)) + } + Inner::NummultiRange => { + &Kind::Range(Type(Inner::Numeric)) + } + Inner::TsmultiRange => { + &Kind::Range(Type(Inner::Timestamp)) + } + Inner::TstzmultiRange => { + &Kind::Range(Type(Inner::Timestamptz)) + } + Inner::DatemultiRange => { + &Kind::Range(Type(Inner::Date)) + } + Inner::Int8multiRange => { + &Kind::Range(Type(Inner::Int8)) + } + Inner::AnymultiRange => { + &Kind::Pseudo + } + Inner::AnycompatiblemultiRange => { + &Kind::Pseudo + } + Inner::PgBrinBloomSummary => { + &Kind::Simple + } + Inner::PgBrinMinmaxMultiSummary => { + &Kind::Simple + } + Inner::PgMcvList => { + &Kind::Simple + } + Inner::PgSnapshot => { + &Kind::Simple + } + Inner::PgSnapshotArray => { + &Kind::Array(Type(Inner::PgSnapshot)) + } + Inner::Xid8 => { + &Kind::Simple + } + Inner::Anycompatible => { + &Kind::Pseudo + } + Inner::Anycompatiblearray => { + &Kind::Pseudo + } + Inner::Anycompatiblenonarray => { + &Kind::Pseudo + } + Inner::AnycompatibleRange => { + &Kind::Pseudo + } + Inner::Int4multiRangeArray => { + &Kind::Array(Type(Inner::Int4multiRange)) + } + Inner::NummultiRangeArray => { + &Kind::Array(Type(Inner::NummultiRange)) + } + Inner::TsmultiRangeArray => { + &Kind::Array(Type(Inner::TsmultiRange)) + } + Inner::TstzmultiRangeArray => { + &Kind::Array(Type(Inner::TstzmultiRange)) + } + Inner::DatemultiRangeArray => { + &Kind::Array(Type(Inner::DatemultiRange)) + } + Inner::Int8multiRangeArray => { + &Kind::Array(Type(Inner::Int8multiRange)) + } Inner::Other(ref u) => &u.kind, } } @@ -874,6 +1308,16 @@ impl Inner { Inner::RegroleArray => "_regrole", Inner::Regcollation => "regcollation", Inner::RegcollationArray => "_regcollation", + Inner::Int4multiRange => "int4multirange", + Inner::NummultiRange => "nummultirange", + Inner::TsmultiRange => "tsmultirange", + Inner::TstzmultiRange => "tstzmultirange", + Inner::DatemultiRange => "datemultirange", + Inner::Int8multiRange => "int8multirange", + Inner::AnymultiRange => "anymultirange", + Inner::AnycompatiblemultiRange => "anycompatiblemultirange", + Inner::PgBrinBloomSummary => "pg_brin_bloom_summary", + Inner::PgBrinMinmaxMultiSummary => "pg_brin_minmax_multi_summary", Inner::PgMcvList => "pg_mcv_list", Inner::PgSnapshot => "pg_snapshot", Inner::PgSnapshotArray => "_pg_snapshot", @@ -882,6 +1326,12 @@ impl Inner { Inner::Anycompatiblearray => "anycompatiblearray", Inner::Anycompatiblenonarray => "anycompatiblenonarray", Inner::AnycompatibleRange => "anycompatiblerange", + Inner::Int4multiRangeArray => "_int4multirange", + Inner::NummultiRangeArray => "_nummultirange", + Inner::TsmultiRangeArray => "_tsmultirange", + Inner::TstzmultiRangeArray => "_tstzmultirange", + Inner::DatemultiRangeArray => "_datemultirange", + Inner::Int8multiRangeArray => "_int8multirange", Inner::Other(ref u) => &u.name, } } @@ -1370,6 +1820,36 @@ impl Type { /// REGCOLLATION[] pub const REGCOLLATION_ARRAY: Type = Type(Inner::RegcollationArray); + /// INT4MULTIRANGE - multirange of integers + pub const INT4MULTI_RANGE: Type = Type(Inner::Int4multiRange); + + /// NUMMULTIRANGE - multirange of numerics + pub const NUMMULTI_RANGE: Type = Type(Inner::NummultiRange); + + /// TSMULTIRANGE - multirange of timestamps without time zone + pub const TSMULTI_RANGE: Type = Type(Inner::TsmultiRange); + + /// TSTZMULTIRANGE - multirange of timestamps with time zone + pub const TSTZMULTI_RANGE: Type = Type(Inner::TstzmultiRange); + + /// DATEMULTIRANGE - multirange of dates + pub const DATEMULTI_RANGE: Type = Type(Inner::DatemultiRange); + + /// INT8MULTIRANGE - multirange of bigints + pub const INT8MULTI_RANGE: Type = Type(Inner::Int8multiRange); + + /// ANYMULTIRANGE - pseudo-type representing a polymorphic base type that is a multirange + pub const ANYMULTI_RANGE: Type = Type(Inner::AnymultiRange); + + /// ANYCOMPATIBLEMULTIRANGE - pseudo-type representing a multirange over a polymorphic common type + pub const ANYCOMPATIBLEMULTI_RANGE: Type = Type(Inner::AnycompatiblemultiRange); + + /// PG_BRIN_BLOOM_SUMMARY - BRIN bloom summary + pub const PG_BRIN_BLOOM_SUMMARY: Type = Type(Inner::PgBrinBloomSummary); + + /// PG_BRIN_MINMAX_MULTI_SUMMARY - BRIN minmax-multi summary + pub const PG_BRIN_MINMAX_MULTI_SUMMARY: Type = Type(Inner::PgBrinMinmaxMultiSummary); + /// PG_MCV_LIST - multivariate MCV list pub const PG_MCV_LIST: Type = Type(Inner::PgMcvList); @@ -1393,4 +1873,22 @@ impl Type { /// ANYCOMPATIBLERANGE - pseudo-type representing a range over a polymorphic common type pub const ANYCOMPATIBLE_RANGE: Type = Type(Inner::AnycompatibleRange); -} + + /// INT4MULTIRANGE[] + pub const INT4MULTI_RANGE_ARRAY: Type = Type(Inner::Int4multiRangeArray); + + /// NUMMULTIRANGE[] + pub const NUMMULTI_RANGE_ARRAY: Type = Type(Inner::NummultiRangeArray); + + /// TSMULTIRANGE[] + pub const TSMULTI_RANGE_ARRAY: Type = Type(Inner::TsmultiRangeArray); + + /// TSTZMULTIRANGE[] + pub const TSTZMULTI_RANGE_ARRAY: Type = Type(Inner::TstzmultiRangeArray); + + /// DATEMULTIRANGE[] + pub const DATEMULTI_RANGE_ARRAY: Type = Type(Inner::DatemultiRangeArray); + + /// INT8MULTIRANGE[] + pub const INT8MULTI_RANGE_ARRAY: Type = Type(Inner::Int8multiRangeArray); +} \ No newline at end of file diff --git a/tokio-postgres/src/error/sqlstate.rs b/tokio-postgres/src/error/sqlstate.rs index 4eb1ae2d0..6f191fc16 100644 --- a/tokio-postgres/src/error/sqlstate.rs +++ b/tokio-postgres/src/error/sqlstate.rs @@ -114,6 +114,7 @@ impl SqlState { Inner::E2203D => "2203D", Inner::E2203E => "2203E", Inner::E2203F => "2203F", + Inner::E2203G => "2203G", Inner::E23000 => "23000", Inner::E23001 => "23001", Inner::E23502 => "23502", @@ -278,7 +279,7 @@ impl SqlState { Inner::Other(code) => code, } } - + /// 00000 pub const SUCCESSFUL_COMPLETION: SqlState = SqlState(Inner::E00000); @@ -364,8 +365,7 @@ impl SqlState { pub const DIAGNOSTICS_EXCEPTION: SqlState = SqlState(Inner::E0Z000); /// 0Z002 - pub const STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER: SqlState = - SqlState(Inner::E0Z002); + pub const STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER: SqlState = SqlState(Inner::E0Z002); /// 20000 pub const CASE_NOT_FOUND: SqlState = SqlState(Inner::E20000); @@ -580,6 +580,9 @@ impl SqlState { /// 2203F pub const SQL_JSON_SCALAR_REQUIRED: SqlState = SqlState(Inner::E2203F); + /// 2203G + pub const SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE: SqlState = SqlState(Inner::E2203G); + /// 23000 pub const INTEGRITY_CONSTRAINT_VIOLATION: SqlState = SqlState(Inner::E23000); @@ -620,8 +623,7 @@ impl SqlState { pub const INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION: SqlState = SqlState(Inner::E25003); /// 25004 - pub const INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION: SqlState = - SqlState(Inner::E25004); + pub const INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION: SqlState = SqlState(Inner::E25004); /// 25005 pub const NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION: SqlState = SqlState(Inner::E25005); @@ -1178,6 +1180,7 @@ enum Inner { E2203D, E2203E, E2203F, + E2203G, E23000, E23001, E23502, @@ -1341,324 +1344,325 @@ enum Inner { EXX002, Other(Box), } - + #[rustfmt::skip] static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ::phf::Map { key: 12913932095322966823, disps: &[ + (0, 24), (0, 12), - (0, 18), - (0, 25), - (0, 109), - (0, 147), (0, 74), - (0, 0), - (7, 117), - (5, 221), - (0, 26), - (1, 45), - (0, 93), - (0, 25), - (0, 61), - (1, 221), - (10, 17), - (0, 77), - (2, 3), - (0, 216), - (0, 0), - (0, 1), - (1, 168), - (0, 64), - (0, 2), - (0, 7), - (1, 37), - (0, 83), - (3, 24), - (0, 0), (0, 109), - (18, 9), - (1, 230), + (0, 11), + (0, 9), (0, 0), - (0, 4), + (4, 38), + (3, 155), + (0, 6), + (1, 242), + (0, 66), + (0, 53), + (5, 180), + (3, 221), + (7, 230), + (0, 125), + (1, 46), + (0, 11), + (1, 2), + (0, 5), + (0, 13), (0, 171), + (0, 15), + (0, 4), + (0, 22), + (1, 85), + (0, 75), + (2, 0), + (1, 25), + (7, 47), + (0, 45), + (0, 35), + (0, 7), + (7, 124), (0, 0), - (34, 97), - (2, 126), - (44, 49), - (5, 182), - (0, 1), + (14, 104), + (1, 183), + (61, 50), + (3, 76), + (0, 12), + (0, 7), + (4, 189), (0, 1), - (0, 71), - (0, 4), - (5, 164), + (64, 102), (0, 0), - (0, 96), - (13, 58), - (0, 58), - (0, 242), - (0, 72), - (16, 53), + (16, 192), + (24, 19), + (0, 5), + (0, 87), + (0, 89), + (0, 14), ], entries: &[ - ("22034", SqlState::MORE_THAN_ONE_SQL_JSON_ITEM), - ("40P01", SqlState::T_R_DEADLOCK_DETECTED), - ("42703", SqlState::UNDEFINED_COLUMN), - ("42P07", SqlState::DUPLICATE_TABLE), - ("55P04", SqlState::UNSAFE_NEW_ENUM_VALUE_USAGE), + ("2F000", SqlState::SQL_ROUTINE_EXCEPTION), + ("01008", SqlState::WARNING_IMPLICIT_ZERO_BIT_PADDING), + ("42501", SqlState::INSUFFICIENT_PRIVILEGE), + ("22000", SqlState::DATA_EXCEPTION), + ("0100C", SqlState::WARNING_DYNAMIC_RESULT_SETS_RETURNED), + ("2200N", SqlState::INVALID_XML_CONTENT), + ("40001", SqlState::T_R_SERIALIZATION_FAILURE), + ("28P01", SqlState::INVALID_PASSWORD), + ("38000", SqlState::EXTERNAL_ROUTINE_EXCEPTION), ("25006", SqlState::READ_ONLY_SQL_TRANSACTION), - ("2201X", SqlState::INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE), - ("HV021", SqlState::FDW_INCONSISTENT_DESCRIPTOR_INFORMATION), - ("42P02", SqlState::UNDEFINED_PARAMETER), - ("HV00C", SqlState::FDW_INVALID_OPTION_INDEX), - ("08003", SqlState::CONNECTION_DOES_NOT_EXIST), - ("02000", SqlState::NO_DATA), - ("24000", SqlState::INVALID_CURSOR_STATE), - ("2203C", SqlState::SQL_JSON_OBJECT_NOT_FOUND), - ("42601", SqlState::SYNTAX_ERROR), - ("22012", SqlState::DIVISION_BY_ZERO), - ("2203B", SqlState::SQL_JSON_NUMBER_NOT_FOUND), - ("P0003", SqlState::TOO_MANY_ROWS), - ("57P04", SqlState::DATABASE_DROPPED), - ("27000", SqlState::TRIGGERED_DATA_CHANGE_VIOLATION), + ("2203D", SqlState::TOO_MANY_JSON_ARRAY_ELEMENTS), + ("42P09", SqlState::AMBIGUOUS_ALIAS), + ("F0000", SqlState::CONFIG_FILE_ERROR), + ("42P18", SqlState::INDETERMINATE_DATATYPE), + ("40002", SqlState::T_R_INTEGRITY_CONSTRAINT_VIOLATION), + ("22009", SqlState::INVALID_TIME_ZONE_DISPLACEMENT_VALUE), ("42P08", SqlState::AMBIGUOUS_PARAMETER), - ("3F000", SqlState::INVALID_SCHEMA_NAME), - ("42883", SqlState::UNDEFINED_FUNCTION), - ("20000", SqlState::CASE_NOT_FOUND), + ("08000", SqlState::CONNECTION_EXCEPTION), + ("25P01", SqlState::NO_ACTIVE_SQL_TRANSACTION), + ("22024", SqlState::UNTERMINATED_C_STRING), + ("55000", SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE), + ("25001", SqlState::ACTIVE_SQL_TRANSACTION), + ("03000", SqlState::SQL_STATEMENT_NOT_YET_COMPLETE), + ("42710", SqlState::DUPLICATE_OBJECT), + ("2D000", SqlState::INVALID_TRANSACTION_TERMINATION), ("2200G", SqlState::MOST_SPECIFIC_TYPE_MISMATCH), - ("42939", SqlState::RESERVED_NAME), - ("42602", SqlState::INVALID_NAME), - ("HV004", SqlState::FDW_INVALID_DATA_TYPE), - ("HV007", SqlState::FDW_INVALID_COLUMN_NAME), + ("22022", SqlState::INDICATOR_OVERFLOW), + ("55006", SqlState::OBJECT_IN_USE), + ("53200", SqlState::OUT_OF_MEMORY), + ("22012", SqlState::DIVISION_BY_ZERO), + ("P0002", SqlState::NO_DATA_FOUND), + ("XX001", SqlState::DATA_CORRUPTED), + ("22P05", SqlState::UNTRANSLATABLE_CHARACTER), + ("40003", SqlState::T_R_STATEMENT_COMPLETION_UNKNOWN), + ("22021", SqlState::CHARACTER_NOT_IN_REPERTOIRE), + ("25000", SqlState::INVALID_TRANSACTION_STATE), + ("42P15", SqlState::INVALID_SCHEMA_DEFINITION), + ("0B000", SqlState::INVALID_TRANSACTION_INITIATION), + ("22004", SqlState::NULL_VALUE_NOT_ALLOWED), + ("42804", SqlState::DATATYPE_MISMATCH), + ("42803", SqlState::GROUPING_ERROR), + ("02001", SqlState::NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED), + ("25002", SqlState::BRANCH_TRANSACTION_ALREADY_ACTIVE), + ("28000", SqlState::INVALID_AUTHORIZATION_SPECIFICATION), + ("HV009", SqlState::FDW_INVALID_USE_OF_NULL_POINTER), + ("22P01", SqlState::FLOATING_POINT_EXCEPTION), + ("2B000", SqlState::DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST), + ("42723", SqlState::DUPLICATE_FUNCTION), + ("21000", SqlState::CARDINALITY_VIOLATION), + ("0Z002", SqlState::STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER), + ("23505", SqlState::UNIQUE_VIOLATION), + ("HV00J", SqlState::FDW_OPTION_NAME_NOT_FOUND), + ("23P01", SqlState::EXCLUSION_VIOLATION), + ("39P03", SqlState::E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED), + ("42P10", SqlState::INVALID_COLUMN_REFERENCE), + ("2202H", SqlState::INVALID_TABLESAMPLE_ARGUMENT), + ("55P04", SqlState::UNSAFE_NEW_ENUM_VALUE_USAGE), + ("P0000", SqlState::PLPGSQL_ERROR), ("2F005", SqlState::S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT), - ("22030", SqlState::DUPLICATE_JSON_OBJECT_KEY_VALUE), - ("53100", SqlState::DISK_FULL), + ("HV00M", SqlState::FDW_UNABLE_TO_CREATE_REPLY), + ("0A000", SqlState::FEATURE_NOT_SUPPORTED), + ("24000", SqlState::INVALID_CURSOR_STATE), + ("25008", SqlState::HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL), + ("01003", SqlState::WARNING_NULL_VALUE_ELIMINATED_IN_SET_FUNCTION), + ("42712", SqlState::DUPLICATE_ALIAS), + ("HV014", SqlState::FDW_TOO_MANY_HANDLES), + ("58030", SqlState::IO_ERROR), + ("2201W", SqlState::INVALID_ROW_COUNT_IN_LIMIT_CLAUSE), + ("22033", SqlState::INVALID_SQL_JSON_SUBSCRIPT), + ("2BP01", SqlState::DEPENDENT_OBJECTS_STILL_EXIST), ("HV005", SqlState::FDW_COLUMN_NAME_NOT_FOUND), + ("25004", SqlState::INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION), + ("54000", SqlState::PROGRAM_LIMIT_EXCEEDED), + ("20000", SqlState::CASE_NOT_FOUND), + ("2203G", SqlState::SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE), + ("22038", SqlState::SINGLETON_SQL_JSON_ITEM_REQUIRED), + ("22007", SqlState::INVALID_DATETIME_FORMAT), + ("08004", SqlState::SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION), ("2200H", SqlState::SEQUENCE_GENERATOR_LIMIT_EXCEEDED), - ("2201W", SqlState::INVALID_ROW_COUNT_IN_LIMIT_CLAUSE), - ("42712", SqlState::DUPLICATE_ALIAS), - ("42622", SqlState::NAME_TOO_LONG), - ("22035", SqlState::NO_SQL_JSON_ITEM), - ("42P18", SqlState::INDETERMINATE_DATATYPE), - ("39P01", SqlState::E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), - ("01000", SqlState::WARNING), - ("2F004", SqlState::S_R_E_READING_SQL_DATA_NOT_PERMITTED), - ("22023", SqlState::INVALID_PARAMETER_VALUE), - ("2200T", SqlState::INVALID_XML_PROCESSING_INSTRUCTION), - ("22013", SqlState::INVALID_PRECEDING_OR_FOLLOWING_SIZE), - ("57P01", SqlState::ADMIN_SHUTDOWN), - ("2202E", SqlState::ARRAY_ELEMENT_ERROR), + ("HV00D", SqlState::FDW_INVALID_OPTION_NAME), + ("P0004", SqlState::ASSERT_FAILURE), ("22018", SqlState::INVALID_CHARACTER_VALUE_FOR_CAST), - ("0F000", SqlState::LOCATOR_EXCEPTION), - ("2D000", SqlState::INVALID_TRANSACTION_TERMINATION), - ("HV009", SqlState::FDW_INVALID_USE_OF_NULL_POINTER), - ("57000", SqlState::OPERATOR_INTERVENTION), - ("25002", SqlState::BRANCH_TRANSACTION_ALREADY_ACTIVE), - ("25004", SqlState::INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION), - ("22009", SqlState::INVALID_TIME_ZONE_DISPLACEMENT_VALUE), - ("HV090", SqlState::FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH), - ("42725", SqlState::AMBIGUOUS_FUNCTION), - ("2F003", SqlState::S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), - ("44000", SqlState::WITH_CHECK_OPTION_VIOLATION), - ("22032", SqlState::INVALID_JSON_TEXT), - ("22036", SqlState::NON_NUMERIC_SQL_JSON_ITEM), - ("2201E", SqlState::INVALID_ARGUMENT_FOR_LOG), - ("25P02", SqlState::IN_FAILED_SQL_TRANSACTION), - ("22001", SqlState::STRING_DATA_RIGHT_TRUNCATION), - ("2201F", SqlState::INVALID_ARGUMENT_FOR_POWER_FUNCTION), - ("01006", SqlState::WARNING_PRIVILEGE_NOT_REVOKED), - ("428C9", SqlState::GENERATED_ALWAYS), - ("22003", SqlState::NUMERIC_VALUE_OUT_OF_RANGE), - ("22P01", SqlState::FLOATING_POINT_EXCEPTION), - ("HV00M", SqlState::FDW_UNABLE_TO_CREATE_REPLY), - ("2201G", SqlState::INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION), - ("34000", SqlState::INVALID_CURSOR_NAME), - ("42846", SqlState::CANNOT_COERCE), - ("2201B", SqlState::INVALID_REGULAR_EXPRESSION), - ("2202G", SqlState::INVALID_TABLESAMPLE_REPEAT), - ("42704", SqlState::UNDEFINED_OBJECT), - ("72000", SqlState::SNAPSHOT_TOO_OLD), - ("53400", SqlState::CONFIGURATION_LIMIT_EXCEEDED), - ("HV00L", SqlState::FDW_UNABLE_TO_CREATE_EXECUTION), - ("2B000", SqlState::DEPENDENT_PRIVILEGE_DESCRIPTORS_STILL_EXIST), - ("22010", SqlState::INVALID_INDICATOR_PARAMETER_VALUE), + ("0L000", SqlState::INVALID_GRANTOR), + ("22P04", SqlState::BAD_COPY_FILE_FORMAT), + ("22031", SqlState::INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION), + ("01P01", SqlState::WARNING_DEPRECATED_FEATURE), + ("0LP01", SqlState::INVALID_GRANT_OPERATION), + ("58P02", SqlState::DUPLICATE_FILE), + ("26000", SqlState::INVALID_SQL_STATEMENT_NAME), ("54001", SqlState::STATEMENT_TOO_COMPLEX), - ("53200", SqlState::OUT_OF_MEMORY), - ("38001", SqlState::E_R_E_CONTAINING_SQL_NOT_PERMITTED), - ("22022", SqlState::INDICATOR_OVERFLOW), - ("2203E", SqlState::TOO_MANY_JSON_OBJECT_MEMBERS), - ("XX000", SqlState::INTERNAL_ERROR), - ("22025", SqlState::INVALID_ESCAPE_SEQUENCE), - ("09000", SqlState::TRIGGERED_ACTION_EXCEPTION), - ("HV008", SqlState::FDW_INVALID_COLUMN_NUMBER), - ("25P01", SqlState::NO_ACTIVE_SQL_TRANSACTION), - ("23505", SqlState::UNIQUE_VIOLATION), - ("3B000", SqlState::SAVEPOINT_EXCEPTION), - ("F0000", SqlState::CONFIG_FILE_ERROR), + ("22010", SqlState::INVALID_INDICATOR_PARAMETER_VALUE), + ("HV00C", SqlState::FDW_INVALID_OPTION_INDEX), + ("22008", SqlState::DATETIME_FIELD_OVERFLOW), + ("42P06", SqlState::DUPLICATE_SCHEMA), + ("25007", SqlState::SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED), + ("42P20", SqlState::WINDOWING_ERROR), + ("HV091", SqlState::FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER), + ("HV021", SqlState::FDW_INCONSISTENT_DESCRIPTOR_INFORMATION), + ("42702", SqlState::AMBIGUOUS_COLUMN), + ("02000", SqlState::NO_DATA), ("54011", SqlState::TOO_MANY_COLUMNS), - ("XX002", SqlState::INDEX_CORRUPTED), - ("2203F", SqlState::SQL_JSON_SCALAR_REQUIRED), + ("HV004", SqlState::FDW_INVALID_DATA_TYPE), + ("01006", SqlState::WARNING_PRIVILEGE_NOT_REVOKED), + ("42701", SqlState::DUPLICATE_COLUMN), + ("08P01", SqlState::PROTOCOL_VIOLATION), + ("42622", SqlState::NAME_TOO_LONG), + ("P0003", SqlState::TOO_MANY_ROWS), + ("22003", SqlState::NUMERIC_VALUE_OUT_OF_RANGE), + ("42P03", SqlState::DUPLICATE_CURSOR), + ("23001", SqlState::RESTRICT_VIOLATION), + ("57000", SqlState::OPERATOR_INTERVENTION), + ("22027", SqlState::TRIM_ERROR), ("42P12", SqlState::INVALID_DATABASE_DEFINITION), + ("3B000", SqlState::SAVEPOINT_EXCEPTION), + ("2201B", SqlState::INVALID_REGULAR_EXPRESSION), + ("22030", SqlState::DUPLICATE_JSON_OBJECT_KEY_VALUE), + ("2F004", SqlState::S_R_E_READING_SQL_DATA_NOT_PERMITTED), + ("428C9", SqlState::GENERATED_ALWAYS), + ("2200S", SqlState::INVALID_XML_COMMENT), + ("22039", SqlState::SQL_JSON_ARRAY_NOT_FOUND), + ("42809", SqlState::WRONG_OBJECT_TYPE), + ("2201X", SqlState::INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE), + ("39001", SqlState::E_R_I_E_INVALID_SQLSTATE_RETURNED), + ("25P02", SqlState::IN_FAILED_SQL_TRANSACTION), + ("0P000", SqlState::INVALID_ROLE_SPECIFICATION), + ("HV00N", SqlState::FDW_UNABLE_TO_ESTABLISH_CONNECTION), + ("53100", SqlState::DISK_FULL), + ("42601", SqlState::SYNTAX_ERROR), + ("23000", SqlState::INTEGRITY_CONSTRAINT_VIOLATION), + ("HV006", SqlState::FDW_INVALID_DATA_TYPE_DESCRIPTORS), ("HV00B", SqlState::FDW_INVALID_HANDLE), - ("55006", SqlState::OBJECT_IN_USE), - ("42P01", SqlState::UNDEFINED_TABLE), - ("25P03", SqlState::IDLE_IN_TRANSACTION_SESSION_TIMEOUT), - ("57P05", SqlState::IDLE_SESSION_TIMEOUT), + ("HV00Q", SqlState::FDW_SCHEMA_NOT_FOUND), + ("01000", SqlState::WARNING), + ("42883", SqlState::UNDEFINED_FUNCTION), + ("57P01", SqlState::ADMIN_SHUTDOWN), ("22037", SqlState::NON_UNIQUE_KEYS_IN_A_JSON_OBJECT), - ("2203A", SqlState::SQL_JSON_MEMBER_NOT_FOUND), - ("P0004", SqlState::ASSERT_FAILURE), - ("58000", SqlState::SYSTEM_ERROR), - ("42P21", SqlState::COLLATION_MISMATCH), - ("57P02", SqlState::CRASH_SHUTDOWN), - ("42830", SqlState::INVALID_FOREIGN_KEY), - ("0LP01", SqlState::INVALID_GRANT_OPERATION), - ("22P02", SqlState::INVALID_TEXT_REPRESENTATION), - ("22039", SqlState::SQL_JSON_ARRAY_NOT_FOUND), - ("28P01", SqlState::INVALID_PASSWORD), - ("22011", SqlState::SUBSTRING_ERROR), - ("HV00J", SqlState::FDW_OPTION_NAME_NOT_FOUND), - ("2200C", SqlState::INVALID_USE_OF_ESCAPE_CHARACTER), - ("08006", SqlState::CONNECTION_FAILURE), - ("22021", SqlState::CHARACTER_NOT_IN_REPERTOIRE), - ("21000", SqlState::CARDINALITY_VIOLATION), - ("42803", SqlState::GROUPING_ERROR), ("00000", SqlState::SUCCESSFUL_COMPLETION), + ("55P03", SqlState::LOCK_NOT_AVAILABLE), + ("42P01", SqlState::UNDEFINED_TABLE), + ("42830", SqlState::INVALID_FOREIGN_KEY), + ("22005", SqlState::ERROR_IN_ASSIGNMENT), + ("22025", SqlState::INVALID_ESCAPE_SEQUENCE), + ("XX002", SqlState::INDEX_CORRUPTED), ("42P16", SqlState::INVALID_TABLE_DEFINITION), - ("38002", SqlState::E_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED), - ("57P03", SqlState::CANNOT_CONNECT_NOW), + ("55P02", SqlState::CANT_CHANGE_RUNTIME_PARAM), + ("22019", SqlState::INVALID_ESCAPE_CHARACTER), + ("P0001", SqlState::RAISE_EXCEPTION), + ("72000", SqlState::SNAPSHOT_TOO_OLD), + ("42P11", SqlState::INVALID_CURSOR_DEFINITION), + ("40P01", SqlState::T_R_DEADLOCK_DETECTED), + ("57P02", SqlState::CRASH_SHUTDOWN), + ("HV00A", SqlState::FDW_INVALID_STRING_FORMAT), + ("2F002", SqlState::S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED), + ("23503", SqlState::FOREIGN_KEY_VIOLATION), + ("40000", SqlState::TRANSACTION_ROLLBACK), + ("22032", SqlState::INVALID_JSON_TEXT), + ("2202E", SqlState::ARRAY_ELEMENT_ERROR), + ("42P19", SqlState::INVALID_RECURSION), + ("42611", SqlState::INVALID_COLUMN_DEFINITION), + ("42P13", SqlState::INVALID_FUNCTION_DEFINITION), + ("25003", SqlState::INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION), + ("39P02", SqlState::E_R_I_E_SRF_PROTOCOL_VIOLATED), + ("XX000", SqlState::INTERNAL_ERROR), + ("08006", SqlState::CONNECTION_FAILURE), + ("57P04", SqlState::DATABASE_DROPPED), + ("42P07", SqlState::DUPLICATE_TABLE), + ("22P03", SqlState::INVALID_BINARY_REPRESENTATION), + ("22035", SqlState::NO_SQL_JSON_ITEM), + ("42P14", SqlState::INVALID_PSTATEMENT_DEFINITION), + ("01007", SqlState::WARNING_PRIVILEGE_NOT_GRANTED), + ("38004", SqlState::E_R_E_READING_SQL_DATA_NOT_PERMITTED), + ("42P21", SqlState::COLLATION_MISMATCH), + ("0Z000", SqlState::DIAGNOSTICS_EXCEPTION), + ("HV001", SqlState::FDW_OUT_OF_MEMORY), + ("0F000", SqlState::LOCATOR_EXCEPTION), + ("22013", SqlState::INVALID_PRECEDING_OR_FOLLOWING_SIZE), + ("2201E", SqlState::INVALID_ARGUMENT_FOR_LOG), + ("22011", SqlState::SUBSTRING_ERROR), + ("42602", SqlState::INVALID_NAME), ("01004", SqlState::WARNING_STRING_DATA_RIGHT_TRUNCATION), - ("HV00K", SqlState::FDW_REPLY_HANDLE), - ("42P06", SqlState::DUPLICATE_SCHEMA), - ("54000", SqlState::PROGRAM_LIMIT_EXCEEDED), - ("2200S", SqlState::INVALID_XML_COMMENT), - ("42000", SqlState::SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION), - ("42P03", SqlState::DUPLICATE_CURSOR), + ("42P02", SqlState::UNDEFINED_PARAMETER), + ("2203C", SqlState::SQL_JSON_OBJECT_NOT_FOUND), ("HV002", SqlState::FDW_DYNAMIC_PARAMETER_VALUE_NEEDED), - ("2202H", SqlState::INVALID_TABLESAMPLE_ARGUMENT), - ("08001", SqlState::SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION), - ("0L000", SqlState::INVALID_GRANTOR), - ("2200L", SqlState::NOT_AN_XML_DOCUMENT), - ("HV006", SqlState::FDW_INVALID_DATA_TYPE_DESCRIPTORS), - ("55000", SqlState::OBJECT_NOT_IN_PREREQUISITE_STATE), + ("0F001", SqlState::L_E_INVALID_SPECIFICATION), ("58P01", SqlState::UNDEFINED_FILE), - ("0B000", SqlState::INVALID_TRANSACTION_INITIATION), - ("22000", SqlState::DATA_EXCEPTION), - ("HV00R", SqlState::FDW_TABLE_NOT_FOUND), - ("2F002", SqlState::S_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED), - ("01007", SqlState::WARNING_PRIVILEGE_NOT_GRANTED), - ("42P19", SqlState::INVALID_RECURSION), + ("38001", SqlState::E_R_E_CONTAINING_SQL_NOT_PERMITTED), + ("42703", SqlState::UNDEFINED_COLUMN), + ("57P05", SqlState::IDLE_SESSION_TIMEOUT), + ("57P03", SqlState::CANNOT_CONNECT_NOW), + ("HV007", SqlState::FDW_INVALID_COLUMN_NAME), + ("22014", SqlState::INVALID_ARGUMENT_FOR_NTILE), + ("22P06", SqlState::NONSTANDARD_USE_OF_ESCAPE_CHARACTER), + ("2203F", SqlState::SQL_JSON_SCALAR_REQUIRED), + ("2200F", SqlState::ZERO_LENGTH_CHARACTER_STRING), + ("09000", SqlState::TRIGGERED_ACTION_EXCEPTION), + ("2201F", SqlState::INVALID_ARGUMENT_FOR_POWER_FUNCTION), + ("08003", SqlState::CONNECTION_DOES_NOT_EXIST), + ("38002", SqlState::E_R_E_MODIFYING_SQL_DATA_NOT_PERMITTED), + ("F0001", SqlState::LOCK_FILE_EXISTS), + ("42P22", SqlState::INDETERMINATE_COLLATION), + ("2200C", SqlState::INVALID_USE_OF_ESCAPE_CHARACTER), + ("2203E", SqlState::TOO_MANY_JSON_OBJECT_MEMBERS), + ("23514", SqlState::CHECK_VIOLATION), + ("22P02", SqlState::INVALID_TEXT_REPRESENTATION), + ("54023", SqlState::TOO_MANY_ARGUMENTS), + ("2200T", SqlState::INVALID_XML_PROCESSING_INSTRUCTION), ("22016", SqlState::INVALID_ARGUMENT_FOR_NTH_VALUE), - ("42702", SqlState::AMBIGUOUS_COLUMN), - ("25005", SqlState::NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION), - ("22004", SqlState::NULL_VALUE_NOT_ALLOWED), - ("42P05", SqlState::DUPLICATE_PSTATEMENT), - ("39001", SqlState::E_R_I_E_INVALID_SQLSTATE_RETURNED), - ("22038", SqlState::SINGLETON_SQL_JSON_ITEM_REQUIRED), - ("22008", SqlState::DATETIME_FIELD_OVERFLOW), - ("38003", SqlState::E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), - ("53000", SqlState::INSUFFICIENT_RESOURCES), + ("25P03", SqlState::IDLE_IN_TRANSACTION_SESSION_TIMEOUT), ("3B001", SqlState::S_E_INVALID_SPECIFICATION), - ("28000", SqlState::INVALID_AUTHORIZATION_SPECIFICATION), - ("P0000", SqlState::PLPGSQL_ERROR), - ("38000", SqlState::EXTERNAL_ROUTINE_EXCEPTION), - ("22019", SqlState::INVALID_ESCAPE_CHARACTER), - ("22015", SqlState::INTERVAL_FIELD_OVERFLOW), - ("42710", SqlState::DUPLICATE_OBJECT), - ("2200M", SqlState::INVALID_XML_DOCUMENT), + ("08001", SqlState::SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION), + ("22036", SqlState::NON_NUMERIC_SQL_JSON_ITEM), + ("3F000", SqlState::INVALID_SCHEMA_NAME), + ("39P01", SqlState::E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), + ("22026", SqlState::STRING_DATA_LENGTH_MISMATCH), + ("42P17", SqlState::INVALID_OBJECT_DEFINITION), + ("22034", SqlState::MORE_THAN_ONE_SQL_JSON_ITEM), ("HV000", SqlState::FDW_ERROR), - ("22P05", SqlState::UNTRANSLATABLE_CHARACTER), - ("0100C", SqlState::WARNING_DYNAMIC_RESULT_SETS_RETURNED), - ("55P02", SqlState::CANT_CHANGE_RUNTIME_PARAM), - ("01003", SqlState::WARNING_NULL_VALUE_ELIMINATED_IN_SET_FUNCTION), - ("2200N", SqlState::INVALID_XML_CONTENT), - ("2F000", SqlState::SQL_ROUTINE_EXCEPTION), - ("08007", SqlState::TRANSACTION_RESOLUTION_UNKNOWN), ("2200B", SqlState::ESCAPE_CHARACTER_CONFLICT), - ("22P03", SqlState::INVALID_BINARY_REPRESENTATION), - ("42P09", SqlState::AMBIGUOUS_ALIAS), + ("HV008", SqlState::FDW_INVALID_COLUMN_NUMBER), + ("34000", SqlState::INVALID_CURSOR_NAME), + ("2201G", SqlState::INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION), + ("44000", SqlState::WITH_CHECK_OPTION_VIOLATION), + ("HV010", SqlState::FDW_FUNCTION_SEQUENCE_ERROR), ("39004", SqlState::E_R_I_E_NULL_VALUE_NOT_ALLOWED), - ("23502", SqlState::NOT_NULL_VIOLATION), - ("2203D", SqlState::TOO_MANY_JSON_ARRAY_ELEMENTS), - ("42P15", SqlState::INVALID_SCHEMA_DEFINITION), - ("08004", SqlState::SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION), - ("HV00N", SqlState::FDW_UNABLE_TO_ESTABLISH_CONNECTION), - ("0A000", SqlState::FEATURE_NOT_SUPPORTED), - ("57014", SqlState::QUERY_CANCELED), - ("22033", SqlState::INVALID_SQL_JSON_SUBSCRIPT), - ("0F001", SqlState::L_E_INVALID_SPECIFICATION), - ("HV00A", SqlState::FDW_INVALID_STRING_FORMAT), - ("39P02", SqlState::E_R_I_E_SRF_PROTOCOL_VIOLATED), - ("42701", SqlState::DUPLICATE_COLUMN), - ("42611", SqlState::INVALID_COLUMN_DEFINITION), - ("HV001", SqlState::FDW_OUT_OF_MEMORY), - ("HV091", SqlState::FDW_INVALID_DESCRIPTOR_FIELD_IDENTIFIER), - ("23P01", SqlState::EXCLUSION_VIOLATION), - ("F0001", SqlState::LOCK_FILE_EXISTS), - ("42501", SqlState::INSUFFICIENT_PRIVILEGE), - ("22026", SqlState::STRING_DATA_LENGTH_MISMATCH), - ("54023", SqlState::TOO_MANY_ARGUMENTS), - ("01008", SqlState::WARNING_IMPLICIT_ZERO_BIT_PADDING), - ("42P04", SqlState::DUPLICATE_DATABASE), - ("22027", SqlState::TRIM_ERROR), - ("53300", SqlState::TOO_MANY_CONNECTIONS), - ("0Z002", SqlState::STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER), - ("42P14", SqlState::INVALID_PSTATEMENT_DEFINITION), - ("P0001", SqlState::RAISE_EXCEPTION), - ("HV014", SqlState::FDW_TOO_MANY_HANDLES), - ("40002", SqlState::T_R_INTEGRITY_CONSTRAINT_VIOLATION), + ("22001", SqlState::STRING_DATA_RIGHT_TRUNCATION), ("3D000", SqlState::INVALID_CATALOG_NAME), - ("03000", SqlState::SQL_STATEMENT_NOT_YET_COMPLETE), - ("22024", SqlState::UNTERMINATED_C_STRING), - ("42P13", SqlState::INVALID_FUNCTION_DEFINITION), - ("08000", SqlState::CONNECTION_EXCEPTION), - ("25007", SqlState::SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED), - ("40001", SqlState::T_R_SERIALIZATION_FAILURE), - ("25001", SqlState::ACTIVE_SQL_TRANSACTION), - ("HV00Q", SqlState::FDW_SCHEMA_NOT_FOUND), - ("22P04", SqlState::BAD_COPY_FILE_FORMAT), - ("XX001", SqlState::DATA_CORRUPTED), - ("23503", SqlState::FOREIGN_KEY_VIOLATION), - ("23514", SqlState::CHECK_VIOLATION), - ("42809", SqlState::WRONG_OBJECT_TYPE), - ("2200F", SqlState::ZERO_LENGTH_CHARACTER_STRING), - ("2BP01", SqlState::DEPENDENT_OBJECTS_STILL_EXIST), - ("25008", SqlState::HELD_CURSOR_REQUIRES_SAME_ISOLATION_LEVEL), - ("55P03", SqlState::LOCK_NOT_AVAILABLE), - ("42P22", SqlState::INDETERMINATE_COLLATION), - ("HV00D", SqlState::FDW_INVALID_OPTION_NAME), - ("42P17", SqlState::INVALID_OBJECT_DEFINITION), - ("23001", SqlState::RESTRICT_VIOLATION), - ("22P06", SqlState::NONSTANDARD_USE_OF_ESCAPE_CHARACTER), - ("22031", SqlState::INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION), - ("2200D", SqlState::INVALID_ESCAPE_OCTET), - ("0Z000", SqlState::DIAGNOSTICS_EXCEPTION), - ("HV024", SqlState::FDW_INVALID_ATTRIBUTE_VALUE), - ("22005", SqlState::ERROR_IN_ASSIGNMENT), - ("58P02", SqlState::DUPLICATE_FILE), + ("25005", SqlState::NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION), + ("2200L", SqlState::NOT_AN_XML_DOCUMENT), + ("27000", SqlState::TRIGGERED_DATA_CHANGE_VIOLATION), + ("HV090", SqlState::FDW_INVALID_STRING_LENGTH_OR_BUFFER_LENGTH), + ("42939", SqlState::RESERVED_NAME), + ("58000", SqlState::SYSTEM_ERROR), + ("2200M", SqlState::INVALID_XML_DOCUMENT), + ("HV00L", SqlState::FDW_UNABLE_TO_CREATE_EXECUTION), + ("57014", SqlState::QUERY_CANCELED), + ("23502", SqlState::NOT_NULL_VIOLATION), + ("22002", SqlState::NULL_VALUE_NO_INDICATOR_PARAMETER), + ("HV00R", SqlState::FDW_TABLE_NOT_FOUND), ("HV00P", SqlState::FDW_NO_SCHEMAS), - ("42P10", SqlState::INVALID_COLUMN_REFERENCE), - ("42P20", SqlState::WINDOWING_ERROR), - ("25000", SqlState::INVALID_TRANSACTION_STATE), - ("38004", SqlState::E_R_E_READING_SQL_DATA_NOT_PERMITTED), - ("01P01", SqlState::WARNING_DEPRECATED_FEATURE), - ("40000", SqlState::TRANSACTION_ROLLBACK), - ("58030", SqlState::IO_ERROR), - ("26000", SqlState::INVALID_SQL_STATEMENT_NAME), - ("22007", SqlState::INVALID_DATETIME_FORMAT), - ("23000", SqlState::INTEGRITY_CONSTRAINT_VIOLATION), - ("0P000", SqlState::INVALID_ROLE_SPECIFICATION), - ("22014", SqlState::INVALID_ARGUMENT_FOR_NTILE), - ("P0002", SqlState::NO_DATA_FOUND), - ("39P03", SqlState::E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED), + ("38003", SqlState::E_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), ("39000", SqlState::EXTERNAL_ROUTINE_INVOCATION_EXCEPTION), - ("42P11", SqlState::INVALID_CURSOR_DEFINITION), - ("HV010", SqlState::FDW_FUNCTION_SEQUENCE_ERROR), - ("22002", SqlState::NULL_VALUE_NO_INDICATOR_PARAMETER), - ("08P01", SqlState::PROTOCOL_VIOLATION), - ("42723", SqlState::DUPLICATE_FUNCTION), - ("40003", SqlState::T_R_STATEMENT_COMPLETION_UNKNOWN), - ("25003", SqlState::INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION), - ("02001", SqlState::NO_ADDITIONAL_DYNAMIC_RESULT_SETS_RETURNED), - ("42804", SqlState::DATATYPE_MISMATCH), + ("22015", SqlState::INTERVAL_FIELD_OVERFLOW), + ("HV00K", SqlState::FDW_REPLY_HANDLE), + ("HV024", SqlState::FDW_INVALID_ATTRIBUTE_VALUE), + ("2200D", SqlState::INVALID_ESCAPE_OCTET), + ("08007", SqlState::TRANSACTION_RESOLUTION_UNKNOWN), + ("2F003", SqlState::S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), + ("42725", SqlState::AMBIGUOUS_FUNCTION), + ("2203A", SqlState::SQL_JSON_MEMBER_NOT_FOUND), + ("42846", SqlState::CANNOT_COERCE), + ("42P04", SqlState::DUPLICATE_DATABASE), + ("42000", SqlState::SYNTAX_ERROR_OR_ACCESS_RULE_VIOLATION), + ("2203B", SqlState::SQL_JSON_NUMBER_NOT_FOUND), + ("42P05", SqlState::DUPLICATE_PSTATEMENT), + ("53300", SqlState::TOO_MANY_CONNECTIONS), + ("53400", SqlState::CONFIGURATION_LIMIT_EXCEEDED), + ("42704", SqlState::UNDEFINED_OBJECT), + ("2202G", SqlState::INVALID_TABLESAMPLE_REPEAT), + ("22023", SqlState::INVALID_PARAMETER_VALUE), + ("53000", SqlState::INSUFFICIENT_RESOURCES), ], }; From 0c86f9362fe98a584fb80828650b22417bb661a2 Mon Sep 17 00:00:00 2001 From: Joseph Koshakow Date: Mon, 21 Nov 2022 16:52:58 -0500 Subject: [PATCH 226/420] Add multirange kind and run cargo fmt --- codegen/src/type_gen.rs | 24 +- postgres-types/src/lib.rs | 2 + postgres-types/src/type_gen.rs | 744 +++++++-------------------- tokio-postgres/src/error/sqlstate.rs | 10 +- 4 files changed, 216 insertions(+), 564 deletions(-) diff --git a/codegen/src/type_gen.rs b/codegen/src/type_gen.rs index 249c5530a..fd7a56450 100644 --- a/codegen/src/type_gen.rs +++ b/codegen/src/type_gen.rs @@ -17,6 +17,7 @@ struct Type { variant: String, ident: String, kind: String, + typtype: Option, element: u32, doc: String, } @@ -217,12 +218,18 @@ fn parse_types() -> BTreeMap { continue; } + let typtype = raw_type.get("typtype").cloned(); + let element = match &*kind { - "R" => match &*raw_type["typtype"] { + "R" => match typtype + .as_ref() + .expect("range type must have typtype") + .as_str() + { "r" => range_elements[&oid], "m" => multi_range_elements[&oid], typtype => panic!("invalid range typtype {}", typtype), - } + }, "A" => oids_by_name[&raw_type["typelem"]], _ => 0, }; @@ -248,6 +255,7 @@ fn parse_types() -> BTreeMap { variant, ident, kind: "A".to_string(), + typtype: None, element: oid, doc, }; @@ -259,6 +267,7 @@ fn parse_types() -> BTreeMap { variant, ident, kind, + typtype, element, doc, }; @@ -362,7 +371,16 @@ fn make_impl(w: &mut BufWriter, types: &BTreeMap) { let kind = match &*type_.kind { "P" => "Pseudo".to_owned(), "A" => format!("Array(Type(Inner::{}))", types[&type_.element].variant), - "R" => format!("Range(Type(Inner::{}))", types[&type_.element].variant), + "R" => match type_ + .typtype + .as_ref() + .expect("range type must have typtype") + .as_str() + { + "r" => format!("Range(Type(Inner::{}))", types[&type_.element].variant), + "m" => format!("Multirange(Type(Inner::{}))", types[&type_.element].variant), + typtype => panic!("invalid range typtype {}", typtype), + }, _ => "Simple".to_owned(), }; diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index ca4233f8a..fa49d99eb 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -320,6 +320,8 @@ pub enum Kind { Array(Type), /// A range type along with the type of its elements. Range(Type), + /// A multirange type along with the type of its elements. + Multirange(Type), /// A domain type along with its underlying type. Domain(Type), /// A composite type along with information about its fields. diff --git a/postgres-types/src/type_gen.rs b/postgres-types/src/type_gen.rs index 901fb46e0..a1bc3f85c 100644 --- a/postgres-types/src/type_gen.rs +++ b/postgres-types/src/type_gen.rs @@ -1,7 +1,7 @@ // Autogenerated file - DO NOT EDIT use std::sync::Arc; -use crate::{Type, Oid, Kind}; +use crate::{Kind, Oid, Type}; #[derive(PartialEq, Eq, Debug, Hash)] pub struct Other { @@ -586,561 +586,191 @@ impl Inner { pub fn kind(&self) -> &Kind { match *self { - Inner::Bool => { - &Kind::Simple - } - Inner::Bytea => { - &Kind::Simple - } - Inner::Char => { - &Kind::Simple - } - Inner::Name => { - &Kind::Simple - } - Inner::Int8 => { - &Kind::Simple - } - Inner::Int2 => { - &Kind::Simple - } - Inner::Int2Vector => { - &Kind::Array(Type(Inner::Int2)) - } - Inner::Int4 => { - &Kind::Simple - } - Inner::Regproc => { - &Kind::Simple - } - Inner::Text => { - &Kind::Simple - } - Inner::Oid => { - &Kind::Simple - } - Inner::Tid => { - &Kind::Simple - } - Inner::Xid => { - &Kind::Simple - } - Inner::Cid => { - &Kind::Simple - } - Inner::OidVector => { - &Kind::Array(Type(Inner::Oid)) - } - Inner::PgDdlCommand => { - &Kind::Pseudo - } - Inner::Json => { - &Kind::Simple - } - Inner::Xml => { - &Kind::Simple - } - Inner::XmlArray => { - &Kind::Array(Type(Inner::Xml)) - } - Inner::PgNodeTree => { - &Kind::Simple - } - Inner::JsonArray => { - &Kind::Array(Type(Inner::Json)) - } - Inner::TableAmHandler => { - &Kind::Pseudo - } - Inner::Xid8Array => { - &Kind::Array(Type(Inner::Xid8)) - } - Inner::IndexAmHandler => { - &Kind::Pseudo - } - Inner::Point => { - &Kind::Simple - } - Inner::Lseg => { - &Kind::Simple - } - Inner::Path => { - &Kind::Simple - } - Inner::Box => { - &Kind::Simple - } - Inner::Polygon => { - &Kind::Simple - } - Inner::Line => { - &Kind::Simple - } - Inner::LineArray => { - &Kind::Array(Type(Inner::Line)) - } - Inner::Cidr => { - &Kind::Simple - } - Inner::CidrArray => { - &Kind::Array(Type(Inner::Cidr)) - } - Inner::Float4 => { - &Kind::Simple - } - Inner::Float8 => { - &Kind::Simple - } - Inner::Unknown => { - &Kind::Simple - } - Inner::Circle => { - &Kind::Simple - } - Inner::CircleArray => { - &Kind::Array(Type(Inner::Circle)) - } - Inner::Macaddr8 => { - &Kind::Simple - } - Inner::Macaddr8Array => { - &Kind::Array(Type(Inner::Macaddr8)) - } - Inner::Money => { - &Kind::Simple - } - Inner::MoneyArray => { - &Kind::Array(Type(Inner::Money)) - } - Inner::Macaddr => { - &Kind::Simple - } - Inner::Inet => { - &Kind::Simple - } - Inner::BoolArray => { - &Kind::Array(Type(Inner::Bool)) - } - Inner::ByteaArray => { - &Kind::Array(Type(Inner::Bytea)) - } - Inner::CharArray => { - &Kind::Array(Type(Inner::Char)) - } - Inner::NameArray => { - &Kind::Array(Type(Inner::Name)) - } - Inner::Int2Array => { - &Kind::Array(Type(Inner::Int2)) - } - Inner::Int2VectorArray => { - &Kind::Array(Type(Inner::Int2Vector)) - } - Inner::Int4Array => { - &Kind::Array(Type(Inner::Int4)) - } - Inner::RegprocArray => { - &Kind::Array(Type(Inner::Regproc)) - } - Inner::TextArray => { - &Kind::Array(Type(Inner::Text)) - } - Inner::TidArray => { - &Kind::Array(Type(Inner::Tid)) - } - Inner::XidArray => { - &Kind::Array(Type(Inner::Xid)) - } - Inner::CidArray => { - &Kind::Array(Type(Inner::Cid)) - } - Inner::OidVectorArray => { - &Kind::Array(Type(Inner::OidVector)) - } - Inner::BpcharArray => { - &Kind::Array(Type(Inner::Bpchar)) - } - Inner::VarcharArray => { - &Kind::Array(Type(Inner::Varchar)) - } - Inner::Int8Array => { - &Kind::Array(Type(Inner::Int8)) - } - Inner::PointArray => { - &Kind::Array(Type(Inner::Point)) - } - Inner::LsegArray => { - &Kind::Array(Type(Inner::Lseg)) - } - Inner::PathArray => { - &Kind::Array(Type(Inner::Path)) - } - Inner::BoxArray => { - &Kind::Array(Type(Inner::Box)) - } - Inner::Float4Array => { - &Kind::Array(Type(Inner::Float4)) - } - Inner::Float8Array => { - &Kind::Array(Type(Inner::Float8)) - } - Inner::PolygonArray => { - &Kind::Array(Type(Inner::Polygon)) - } - Inner::OidArray => { - &Kind::Array(Type(Inner::Oid)) - } - Inner::Aclitem => { - &Kind::Simple - } - Inner::AclitemArray => { - &Kind::Array(Type(Inner::Aclitem)) - } - Inner::MacaddrArray => { - &Kind::Array(Type(Inner::Macaddr)) - } - Inner::InetArray => { - &Kind::Array(Type(Inner::Inet)) - } - Inner::Bpchar => { - &Kind::Simple - } - Inner::Varchar => { - &Kind::Simple - } - Inner::Date => { - &Kind::Simple - } - Inner::Time => { - &Kind::Simple - } - Inner::Timestamp => { - &Kind::Simple - } - Inner::TimestampArray => { - &Kind::Array(Type(Inner::Timestamp)) - } - Inner::DateArray => { - &Kind::Array(Type(Inner::Date)) - } - Inner::TimeArray => { - &Kind::Array(Type(Inner::Time)) - } - Inner::Timestamptz => { - &Kind::Simple - } - Inner::TimestamptzArray => { - &Kind::Array(Type(Inner::Timestamptz)) - } - Inner::Interval => { - &Kind::Simple - } - Inner::IntervalArray => { - &Kind::Array(Type(Inner::Interval)) - } - Inner::NumericArray => { - &Kind::Array(Type(Inner::Numeric)) - } - Inner::CstringArray => { - &Kind::Array(Type(Inner::Cstring)) - } - Inner::Timetz => { - &Kind::Simple - } - Inner::TimetzArray => { - &Kind::Array(Type(Inner::Timetz)) - } - Inner::Bit => { - &Kind::Simple - } - Inner::BitArray => { - &Kind::Array(Type(Inner::Bit)) - } - Inner::Varbit => { - &Kind::Simple - } - Inner::VarbitArray => { - &Kind::Array(Type(Inner::Varbit)) - } - Inner::Numeric => { - &Kind::Simple - } - Inner::Refcursor => { - &Kind::Simple - } - Inner::RefcursorArray => { - &Kind::Array(Type(Inner::Refcursor)) - } - Inner::Regprocedure => { - &Kind::Simple - } - Inner::Regoper => { - &Kind::Simple - } - Inner::Regoperator => { - &Kind::Simple - } - Inner::Regclass => { - &Kind::Simple - } - Inner::Regtype => { - &Kind::Simple - } - Inner::RegprocedureArray => { - &Kind::Array(Type(Inner::Regprocedure)) - } - Inner::RegoperArray => { - &Kind::Array(Type(Inner::Regoper)) - } - Inner::RegoperatorArray => { - &Kind::Array(Type(Inner::Regoperator)) - } - Inner::RegclassArray => { - &Kind::Array(Type(Inner::Regclass)) - } - Inner::RegtypeArray => { - &Kind::Array(Type(Inner::Regtype)) - } - Inner::Record => { - &Kind::Pseudo - } - Inner::Cstring => { - &Kind::Pseudo - } - Inner::Any => { - &Kind::Pseudo - } - Inner::Anyarray => { - &Kind::Pseudo - } - Inner::Void => { - &Kind::Pseudo - } - Inner::Trigger => { - &Kind::Pseudo - } - Inner::LanguageHandler => { - &Kind::Pseudo - } - Inner::Internal => { - &Kind::Pseudo - } - Inner::Anyelement => { - &Kind::Pseudo - } - Inner::RecordArray => { - &Kind::Pseudo - } - Inner::Anynonarray => { - &Kind::Pseudo - } - Inner::TxidSnapshotArray => { - &Kind::Array(Type(Inner::TxidSnapshot)) - } - Inner::Uuid => { - &Kind::Simple - } - Inner::UuidArray => { - &Kind::Array(Type(Inner::Uuid)) - } - Inner::TxidSnapshot => { - &Kind::Simple - } - Inner::FdwHandler => { - &Kind::Pseudo - } - Inner::PgLsn => { - &Kind::Simple - } - Inner::PgLsnArray => { - &Kind::Array(Type(Inner::PgLsn)) - } - Inner::TsmHandler => { - &Kind::Pseudo - } - Inner::PgNdistinct => { - &Kind::Simple - } - Inner::PgDependencies => { - &Kind::Simple - } - Inner::Anyenum => { - &Kind::Pseudo - } - Inner::TsVector => { - &Kind::Simple - } - Inner::Tsquery => { - &Kind::Simple - } - Inner::GtsVector => { - &Kind::Simple - } - Inner::TsVectorArray => { - &Kind::Array(Type(Inner::TsVector)) - } - Inner::GtsVectorArray => { - &Kind::Array(Type(Inner::GtsVector)) - } - Inner::TsqueryArray => { - &Kind::Array(Type(Inner::Tsquery)) - } - Inner::Regconfig => { - &Kind::Simple - } - Inner::RegconfigArray => { - &Kind::Array(Type(Inner::Regconfig)) - } - Inner::Regdictionary => { - &Kind::Simple - } - Inner::RegdictionaryArray => { - &Kind::Array(Type(Inner::Regdictionary)) - } - Inner::Jsonb => { - &Kind::Simple - } - Inner::JsonbArray => { - &Kind::Array(Type(Inner::Jsonb)) - } - Inner::AnyRange => { - &Kind::Pseudo - } - Inner::EventTrigger => { - &Kind::Pseudo - } - Inner::Int4Range => { - &Kind::Range(Type(Inner::Int4)) - } - Inner::Int4RangeArray => { - &Kind::Array(Type(Inner::Int4Range)) - } - Inner::NumRange => { - &Kind::Range(Type(Inner::Numeric)) - } - Inner::NumRangeArray => { - &Kind::Array(Type(Inner::NumRange)) - } - Inner::TsRange => { - &Kind::Range(Type(Inner::Timestamp)) - } - Inner::TsRangeArray => { - &Kind::Array(Type(Inner::TsRange)) - } - Inner::TstzRange => { - &Kind::Range(Type(Inner::Timestamptz)) - } - Inner::TstzRangeArray => { - &Kind::Array(Type(Inner::TstzRange)) - } - Inner::DateRange => { - &Kind::Range(Type(Inner::Date)) - } - Inner::DateRangeArray => { - &Kind::Array(Type(Inner::DateRange)) - } - Inner::Int8Range => { - &Kind::Range(Type(Inner::Int8)) - } - Inner::Int8RangeArray => { - &Kind::Array(Type(Inner::Int8Range)) - } - Inner::Jsonpath => { - &Kind::Simple - } - Inner::JsonpathArray => { - &Kind::Array(Type(Inner::Jsonpath)) - } - Inner::Regnamespace => { - &Kind::Simple - } - Inner::RegnamespaceArray => { - &Kind::Array(Type(Inner::Regnamespace)) - } - Inner::Regrole => { - &Kind::Simple - } - Inner::RegroleArray => { - &Kind::Array(Type(Inner::Regrole)) - } - Inner::Regcollation => { - &Kind::Simple - } - Inner::RegcollationArray => { - &Kind::Array(Type(Inner::Regcollation)) - } - Inner::Int4multiRange => { - &Kind::Range(Type(Inner::Int4)) - } - Inner::NummultiRange => { - &Kind::Range(Type(Inner::Numeric)) - } - Inner::TsmultiRange => { - &Kind::Range(Type(Inner::Timestamp)) - } - Inner::TstzmultiRange => { - &Kind::Range(Type(Inner::Timestamptz)) - } - Inner::DatemultiRange => { - &Kind::Range(Type(Inner::Date)) - } - Inner::Int8multiRange => { - &Kind::Range(Type(Inner::Int8)) - } - Inner::AnymultiRange => { - &Kind::Pseudo - } - Inner::AnycompatiblemultiRange => { - &Kind::Pseudo - } - Inner::PgBrinBloomSummary => { - &Kind::Simple - } - Inner::PgBrinMinmaxMultiSummary => { - &Kind::Simple - } - Inner::PgMcvList => { - &Kind::Simple - } - Inner::PgSnapshot => { - &Kind::Simple - } - Inner::PgSnapshotArray => { - &Kind::Array(Type(Inner::PgSnapshot)) - } - Inner::Xid8 => { - &Kind::Simple - } - Inner::Anycompatible => { - &Kind::Pseudo - } - Inner::Anycompatiblearray => { - &Kind::Pseudo - } - Inner::Anycompatiblenonarray => { - &Kind::Pseudo - } - Inner::AnycompatibleRange => { - &Kind::Pseudo - } - Inner::Int4multiRangeArray => { - &Kind::Array(Type(Inner::Int4multiRange)) - } - Inner::NummultiRangeArray => { - &Kind::Array(Type(Inner::NummultiRange)) - } - Inner::TsmultiRangeArray => { - &Kind::Array(Type(Inner::TsmultiRange)) - } - Inner::TstzmultiRangeArray => { - &Kind::Array(Type(Inner::TstzmultiRange)) - } - Inner::DatemultiRangeArray => { - &Kind::Array(Type(Inner::DatemultiRange)) - } - Inner::Int8multiRangeArray => { - &Kind::Array(Type(Inner::Int8multiRange)) - } + Inner::Bool => &Kind::Simple, + Inner::Bytea => &Kind::Simple, + Inner::Char => &Kind::Simple, + Inner::Name => &Kind::Simple, + Inner::Int8 => &Kind::Simple, + Inner::Int2 => &Kind::Simple, + Inner::Int2Vector => &Kind::Array(Type(Inner::Int2)), + Inner::Int4 => &Kind::Simple, + Inner::Regproc => &Kind::Simple, + Inner::Text => &Kind::Simple, + Inner::Oid => &Kind::Simple, + Inner::Tid => &Kind::Simple, + Inner::Xid => &Kind::Simple, + Inner::Cid => &Kind::Simple, + Inner::OidVector => &Kind::Array(Type(Inner::Oid)), + Inner::PgDdlCommand => &Kind::Pseudo, + Inner::Json => &Kind::Simple, + Inner::Xml => &Kind::Simple, + Inner::XmlArray => &Kind::Array(Type(Inner::Xml)), + Inner::PgNodeTree => &Kind::Simple, + Inner::JsonArray => &Kind::Array(Type(Inner::Json)), + Inner::TableAmHandler => &Kind::Pseudo, + Inner::Xid8Array => &Kind::Array(Type(Inner::Xid8)), + Inner::IndexAmHandler => &Kind::Pseudo, + Inner::Point => &Kind::Simple, + Inner::Lseg => &Kind::Simple, + Inner::Path => &Kind::Simple, + Inner::Box => &Kind::Simple, + Inner::Polygon => &Kind::Simple, + Inner::Line => &Kind::Simple, + Inner::LineArray => &Kind::Array(Type(Inner::Line)), + Inner::Cidr => &Kind::Simple, + Inner::CidrArray => &Kind::Array(Type(Inner::Cidr)), + Inner::Float4 => &Kind::Simple, + Inner::Float8 => &Kind::Simple, + Inner::Unknown => &Kind::Simple, + Inner::Circle => &Kind::Simple, + Inner::CircleArray => &Kind::Array(Type(Inner::Circle)), + Inner::Macaddr8 => &Kind::Simple, + Inner::Macaddr8Array => &Kind::Array(Type(Inner::Macaddr8)), + Inner::Money => &Kind::Simple, + Inner::MoneyArray => &Kind::Array(Type(Inner::Money)), + Inner::Macaddr => &Kind::Simple, + Inner::Inet => &Kind::Simple, + Inner::BoolArray => &Kind::Array(Type(Inner::Bool)), + Inner::ByteaArray => &Kind::Array(Type(Inner::Bytea)), + Inner::CharArray => &Kind::Array(Type(Inner::Char)), + Inner::NameArray => &Kind::Array(Type(Inner::Name)), + Inner::Int2Array => &Kind::Array(Type(Inner::Int2)), + Inner::Int2VectorArray => &Kind::Array(Type(Inner::Int2Vector)), + Inner::Int4Array => &Kind::Array(Type(Inner::Int4)), + Inner::RegprocArray => &Kind::Array(Type(Inner::Regproc)), + Inner::TextArray => &Kind::Array(Type(Inner::Text)), + Inner::TidArray => &Kind::Array(Type(Inner::Tid)), + Inner::XidArray => &Kind::Array(Type(Inner::Xid)), + Inner::CidArray => &Kind::Array(Type(Inner::Cid)), + Inner::OidVectorArray => &Kind::Array(Type(Inner::OidVector)), + Inner::BpcharArray => &Kind::Array(Type(Inner::Bpchar)), + Inner::VarcharArray => &Kind::Array(Type(Inner::Varchar)), + Inner::Int8Array => &Kind::Array(Type(Inner::Int8)), + Inner::PointArray => &Kind::Array(Type(Inner::Point)), + Inner::LsegArray => &Kind::Array(Type(Inner::Lseg)), + Inner::PathArray => &Kind::Array(Type(Inner::Path)), + Inner::BoxArray => &Kind::Array(Type(Inner::Box)), + Inner::Float4Array => &Kind::Array(Type(Inner::Float4)), + Inner::Float8Array => &Kind::Array(Type(Inner::Float8)), + Inner::PolygonArray => &Kind::Array(Type(Inner::Polygon)), + Inner::OidArray => &Kind::Array(Type(Inner::Oid)), + Inner::Aclitem => &Kind::Simple, + Inner::AclitemArray => &Kind::Array(Type(Inner::Aclitem)), + Inner::MacaddrArray => &Kind::Array(Type(Inner::Macaddr)), + Inner::InetArray => &Kind::Array(Type(Inner::Inet)), + Inner::Bpchar => &Kind::Simple, + Inner::Varchar => &Kind::Simple, + Inner::Date => &Kind::Simple, + Inner::Time => &Kind::Simple, + Inner::Timestamp => &Kind::Simple, + Inner::TimestampArray => &Kind::Array(Type(Inner::Timestamp)), + Inner::DateArray => &Kind::Array(Type(Inner::Date)), + Inner::TimeArray => &Kind::Array(Type(Inner::Time)), + Inner::Timestamptz => &Kind::Simple, + Inner::TimestamptzArray => &Kind::Array(Type(Inner::Timestamptz)), + Inner::Interval => &Kind::Simple, + Inner::IntervalArray => &Kind::Array(Type(Inner::Interval)), + Inner::NumericArray => &Kind::Array(Type(Inner::Numeric)), + Inner::CstringArray => &Kind::Array(Type(Inner::Cstring)), + Inner::Timetz => &Kind::Simple, + Inner::TimetzArray => &Kind::Array(Type(Inner::Timetz)), + Inner::Bit => &Kind::Simple, + Inner::BitArray => &Kind::Array(Type(Inner::Bit)), + Inner::Varbit => &Kind::Simple, + Inner::VarbitArray => &Kind::Array(Type(Inner::Varbit)), + Inner::Numeric => &Kind::Simple, + Inner::Refcursor => &Kind::Simple, + Inner::RefcursorArray => &Kind::Array(Type(Inner::Refcursor)), + Inner::Regprocedure => &Kind::Simple, + Inner::Regoper => &Kind::Simple, + Inner::Regoperator => &Kind::Simple, + Inner::Regclass => &Kind::Simple, + Inner::Regtype => &Kind::Simple, + Inner::RegprocedureArray => &Kind::Array(Type(Inner::Regprocedure)), + Inner::RegoperArray => &Kind::Array(Type(Inner::Regoper)), + Inner::RegoperatorArray => &Kind::Array(Type(Inner::Regoperator)), + Inner::RegclassArray => &Kind::Array(Type(Inner::Regclass)), + Inner::RegtypeArray => &Kind::Array(Type(Inner::Regtype)), + Inner::Record => &Kind::Pseudo, + Inner::Cstring => &Kind::Pseudo, + Inner::Any => &Kind::Pseudo, + Inner::Anyarray => &Kind::Pseudo, + Inner::Void => &Kind::Pseudo, + Inner::Trigger => &Kind::Pseudo, + Inner::LanguageHandler => &Kind::Pseudo, + Inner::Internal => &Kind::Pseudo, + Inner::Anyelement => &Kind::Pseudo, + Inner::RecordArray => &Kind::Pseudo, + Inner::Anynonarray => &Kind::Pseudo, + Inner::TxidSnapshotArray => &Kind::Array(Type(Inner::TxidSnapshot)), + Inner::Uuid => &Kind::Simple, + Inner::UuidArray => &Kind::Array(Type(Inner::Uuid)), + Inner::TxidSnapshot => &Kind::Simple, + Inner::FdwHandler => &Kind::Pseudo, + Inner::PgLsn => &Kind::Simple, + Inner::PgLsnArray => &Kind::Array(Type(Inner::PgLsn)), + Inner::TsmHandler => &Kind::Pseudo, + Inner::PgNdistinct => &Kind::Simple, + Inner::PgDependencies => &Kind::Simple, + Inner::Anyenum => &Kind::Pseudo, + Inner::TsVector => &Kind::Simple, + Inner::Tsquery => &Kind::Simple, + Inner::GtsVector => &Kind::Simple, + Inner::TsVectorArray => &Kind::Array(Type(Inner::TsVector)), + Inner::GtsVectorArray => &Kind::Array(Type(Inner::GtsVector)), + Inner::TsqueryArray => &Kind::Array(Type(Inner::Tsquery)), + Inner::Regconfig => &Kind::Simple, + Inner::RegconfigArray => &Kind::Array(Type(Inner::Regconfig)), + Inner::Regdictionary => &Kind::Simple, + Inner::RegdictionaryArray => &Kind::Array(Type(Inner::Regdictionary)), + Inner::Jsonb => &Kind::Simple, + Inner::JsonbArray => &Kind::Array(Type(Inner::Jsonb)), + Inner::AnyRange => &Kind::Pseudo, + Inner::EventTrigger => &Kind::Pseudo, + Inner::Int4Range => &Kind::Range(Type(Inner::Int4)), + Inner::Int4RangeArray => &Kind::Array(Type(Inner::Int4Range)), + Inner::NumRange => &Kind::Range(Type(Inner::Numeric)), + Inner::NumRangeArray => &Kind::Array(Type(Inner::NumRange)), + Inner::TsRange => &Kind::Range(Type(Inner::Timestamp)), + Inner::TsRangeArray => &Kind::Array(Type(Inner::TsRange)), + Inner::TstzRange => &Kind::Range(Type(Inner::Timestamptz)), + Inner::TstzRangeArray => &Kind::Array(Type(Inner::TstzRange)), + Inner::DateRange => &Kind::Range(Type(Inner::Date)), + Inner::DateRangeArray => &Kind::Array(Type(Inner::DateRange)), + Inner::Int8Range => &Kind::Range(Type(Inner::Int8)), + Inner::Int8RangeArray => &Kind::Array(Type(Inner::Int8Range)), + Inner::Jsonpath => &Kind::Simple, + Inner::JsonpathArray => &Kind::Array(Type(Inner::Jsonpath)), + Inner::Regnamespace => &Kind::Simple, + Inner::RegnamespaceArray => &Kind::Array(Type(Inner::Regnamespace)), + Inner::Regrole => &Kind::Simple, + Inner::RegroleArray => &Kind::Array(Type(Inner::Regrole)), + Inner::Regcollation => &Kind::Simple, + Inner::RegcollationArray => &Kind::Array(Type(Inner::Regcollation)), + Inner::Int4multiRange => &Kind::Multirange(Type(Inner::Int4)), + Inner::NummultiRange => &Kind::Multirange(Type(Inner::Numeric)), + Inner::TsmultiRange => &Kind::Multirange(Type(Inner::Timestamp)), + Inner::TstzmultiRange => &Kind::Multirange(Type(Inner::Timestamptz)), + Inner::DatemultiRange => &Kind::Multirange(Type(Inner::Date)), + Inner::Int8multiRange => &Kind::Multirange(Type(Inner::Int8)), + Inner::AnymultiRange => &Kind::Pseudo, + Inner::AnycompatiblemultiRange => &Kind::Pseudo, + Inner::PgBrinBloomSummary => &Kind::Simple, + Inner::PgBrinMinmaxMultiSummary => &Kind::Simple, + Inner::PgMcvList => &Kind::Simple, + Inner::PgSnapshot => &Kind::Simple, + Inner::PgSnapshotArray => &Kind::Array(Type(Inner::PgSnapshot)), + Inner::Xid8 => &Kind::Simple, + Inner::Anycompatible => &Kind::Pseudo, + Inner::Anycompatiblearray => &Kind::Pseudo, + Inner::Anycompatiblenonarray => &Kind::Pseudo, + Inner::AnycompatibleRange => &Kind::Pseudo, + Inner::Int4multiRangeArray => &Kind::Array(Type(Inner::Int4multiRange)), + Inner::NummultiRangeArray => &Kind::Array(Type(Inner::NummultiRange)), + Inner::TsmultiRangeArray => &Kind::Array(Type(Inner::TsmultiRange)), + Inner::TstzmultiRangeArray => &Kind::Array(Type(Inner::TstzmultiRange)), + Inner::DatemultiRangeArray => &Kind::Array(Type(Inner::DatemultiRange)), + Inner::Int8multiRangeArray => &Kind::Array(Type(Inner::Int8multiRange)), Inner::Other(ref u) => &u.kind, } } @@ -1891,4 +1521,4 @@ impl Type { /// INT8MULTIRANGE[] pub const INT8MULTI_RANGE_ARRAY: Type = Type(Inner::Int8multiRangeArray); -} \ No newline at end of file +} diff --git a/tokio-postgres/src/error/sqlstate.rs b/tokio-postgres/src/error/sqlstate.rs index 6f191fc16..13a1d75f9 100644 --- a/tokio-postgres/src/error/sqlstate.rs +++ b/tokio-postgres/src/error/sqlstate.rs @@ -279,7 +279,7 @@ impl SqlState { Inner::Other(code) => code, } } - + /// 00000 pub const SUCCESSFUL_COMPLETION: SqlState = SqlState(Inner::E00000); @@ -365,7 +365,8 @@ impl SqlState { pub const DIAGNOSTICS_EXCEPTION: SqlState = SqlState(Inner::E0Z000); /// 0Z002 - pub const STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER: SqlState = SqlState(Inner::E0Z002); + pub const STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER: SqlState = + SqlState(Inner::E0Z002); /// 20000 pub const CASE_NOT_FOUND: SqlState = SqlState(Inner::E20000); @@ -623,7 +624,8 @@ impl SqlState { pub const INAPPROPRIATE_ACCESS_MODE_FOR_BRANCH_TRANSACTION: SqlState = SqlState(Inner::E25003); /// 25004 - pub const INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION: SqlState = SqlState(Inner::E25004); + pub const INAPPROPRIATE_ISOLATION_LEVEL_FOR_BRANCH_TRANSACTION: SqlState = + SqlState(Inner::E25004); /// 25005 pub const NO_ACTIVE_SQL_TRANSACTION_FOR_BRANCH_TRANSACTION: SqlState = SqlState(Inner::E25005); @@ -1344,7 +1346,7 @@ enum Inner { EXX002, Other(Box), } - + #[rustfmt::skip] static SQLSTATE_MAP: phf::Map<&'static str, SqlState> = ::phf::Map { From eaa1c6279393ce8f0967cce7587638bb37135765 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Nov 2022 13:05:23 +0000 Subject: [PATCH 227/420] Update env_logger requirement from 0.9 to 0.10 Updates the requirements on [env_logger](https://github.com/rust-cli/env_logger) to permit the latest version. - [Release notes](https://github.com/rust-cli/env_logger/releases) - [Changelog](https://github.com/rust-cli/env_logger/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-cli/env_logger/compare/v0.9.0...v0.10.0) --- updated-dependencies: - dependency-name: env_logger dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- tokio-postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 760105104..68737f738 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -62,7 +62,7 @@ tokio-util = { version = "0.7", features = ["codec"] } [dev-dependencies] futures-executor = "0.3" criterion = "0.4" -env_logger = "0.9" +env_logger = "0.10" tokio = { version = "1.0", features = [ "macros", "net", From be90d0e848c0be8a6461127b81c7ad966c828ad0 Mon Sep 17 00:00:00 2001 From: xxchan Date: Wed, 7 Dec 2022 12:29:28 +0100 Subject: [PATCH 228/420] derive Debug for SimpleQueryMessage --- postgres-protocol/src/message/backend.rs | 1 + tokio-postgres/src/lib.rs | 1 + tokio-postgres/src/row.rs | 1 + tokio-postgres/src/simple_query.rs | 1 + 4 files changed, 4 insertions(+) diff --git a/postgres-protocol/src/message/backend.rs b/postgres-protocol/src/message/backend.rs index 45e5c4074..3f5374d64 100644 --- a/postgres-protocol/src/message/backend.rs +++ b/postgres-protocol/src/message/backend.rs @@ -524,6 +524,7 @@ impl CopyOutResponseBody { } } +#[derive(Debug)] pub struct DataRowBody { storage: Bytes, len: u16, diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index bd4d7b8ce..a9ecba4f1 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -239,6 +239,7 @@ pub enum AsyncMessage { } /// Message returned by the `SimpleQuery` stream. +#[derive(Debug)] #[non_exhaustive] pub enum SimpleQueryMessage { /// A row of data. diff --git a/tokio-postgres/src/row.rs b/tokio-postgres/src/row.rs index e3ed696c1..db179b432 100644 --- a/tokio-postgres/src/row.rs +++ b/tokio-postgres/src/row.rs @@ -196,6 +196,7 @@ impl AsName for SimpleColumn { } /// A row of data returned from the database by a simple query. +#[derive(Debug)] pub struct SimpleQueryRow { columns: Arc<[SimpleColumn]>, body: DataRowBody, diff --git a/tokio-postgres/src/simple_query.rs b/tokio-postgres/src/simple_query.rs index 19cb10236..7c266e409 100644 --- a/tokio-postgres/src/simple_query.rs +++ b/tokio-postgres/src/simple_query.rs @@ -15,6 +15,7 @@ use std::sync::Arc; use std::task::{Context, Poll}; /// Information about a column of a single query row. +#[derive(Debug)] pub struct SimpleColumn { name: String, } From 748167d5f8a489888209f58492153f52bd9d9e27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 12 Dec 2022 13:07:35 +0000 Subject: [PATCH 229/420] Update base64 requirement from 0.13 to 0.20 Updates the requirements on [base64](https://github.com/marshallpierce/rust-base64) to permit the latest version. - [Release notes](https://github.com/marshallpierce/rust-base64/releases) - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.13.0...v0.20.0) --- updated-dependencies: - dependency-name: base64 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 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 a4716907b..2a72cc60c 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/sfackler/rust-postgres" readme = "../README.md" [dependencies] -base64 = "0.13" +base64 = "0.20" byteorder = "1.0" bytes = "1.0" fallible-iterator = "0.2" From 3697f6b63c67073925e1db4d5bb74f1a4dc8c3f3 Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Fri, 26 Aug 2022 13:46:04 -0700 Subject: [PATCH 230/420] Add hostaddr support --- tokio-postgres/src/config.rs | 70 +++++++++++++++++++++++++++++++++++ tokio-postgres/src/connect.rs | 23 +++++++++++- 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 5b364ec06..0c62b5030 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -13,6 +13,7 @@ use crate::{Client, Connection, Error}; use std::borrow::Cow; #[cfg(unix)] use std::ffi::OsStr; +use std::ops::Deref; #[cfg(unix)] use std::os::unix::ffi::OsStrExt; #[cfg(unix)] @@ -91,6 +92,17 @@ 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. +/// * `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, +/// - or if host specifies an IP address, that value will be used directly. +/// Using `hostaddr` allows the application to avoid a host name look-up, which might be important in applications +/// with time constraints. However, a host name is required for verify-full SSL certificate verification. +/// Note that `host` is always required regardless of whether `hostaddr` is present. +/// * If `host` is specified without `hostaddr`, a host name lookup occurs; +/// * If both `host` and `hostaddr` are specified, the value for `hostaddr` gives the server network address. +/// The value for `host` is ignored unless the authentication method requires it, +/// in which case it will be used as the host name. /// * `port` - The port to connect to. Multiple ports can be specified, separated by commas. The number of ports must be /// either 1, in which case it will be used for all hosts, or the same as the number of hosts. Defaults to 5432 if /// omitted or the empty string. @@ -122,6 +134,10 @@ pub enum Host { /// ``` /// /// ```not_rust +/// host=host1,host2,host3 port=1234,,5678 hostaddr=127.0.0.1,127.0.0.2,127.0.0.3 user=postgres target_session_attrs=read-write +/// ``` +/// +/// ```not_rust /// host=host1,host2,host3 port=1234,,5678 user=postgres target_session_attrs=read-write /// ``` /// @@ -158,6 +174,7 @@ pub struct Config { pub(crate) application_name: Option, pub(crate) ssl_mode: SslMode, pub(crate) host: Vec, + pub(crate) hostaddr: Vec, pub(crate) port: Vec, pub(crate) connect_timeout: Option, pub(crate) keepalives: bool, @@ -188,6 +205,7 @@ impl Config { application_name: None, ssl_mode: SslMode::Prefer, host: vec![], + hostaddr: vec![], port: vec![], connect_timeout: None, keepalives: true, @@ -298,6 +316,11 @@ impl Config { &self.host } + /// Gets the hostaddrs that have been added to the configuration with `hostaddr`. + pub fn get_hostaddrs(&self) -> &[String] { + self.hostaddr.deref() + } + /// Adds a Unix socket host to the configuration. /// /// Unlike `host`, this method allows non-UTF8 paths. @@ -310,6 +333,15 @@ impl Config { self } + /// Adds a hostaddr to the configuration. + /// + /// Multiple hostaddrs can be specified by calling this method multiple times, and each will be tried in order. + /// There must be either no hostaddrs, or the same number of hostaddrs as hosts. + pub fn hostaddr(&mut self, hostaddr: &str) -> &mut Config { + self.hostaddr.push(hostaddr.to_string()); + self + } + /// Adds a port to the configuration. /// /// Multiple ports can be specified by calling this method multiple times. There must either be no ports, in which @@ -455,6 +487,11 @@ impl Config { self.host(host); } } + "hostaddr" => { + for hostaddr in value.split(',') { + self.hostaddr(hostaddr); + } + } "port" => { for port in value.split(',') { let port = if port.is_empty() { @@ -593,6 +630,7 @@ impl fmt::Debug for Config { .field("application_name", &self.application_name) .field("ssl_mode", &self.ssl_mode) .field("host", &self.host) + .field("hostaddr", &self.hostaddr) .field("port", &self.port) .field("connect_timeout", &self.connect_timeout) .field("keepalives", &self.keepalives) @@ -975,3 +1013,35 @@ impl<'a> UrlParser<'a> { .map_err(|e| Error::config_parse(e.into())) } } + +#[cfg(test)] +mod tests { + use crate::{config::Host, Config}; + + #[test] + fn test_simple_parsing() { + let s = "user=pass_user dbname=postgres host=host1,host2 hostaddr=127.0.0.1,127.0.0.2 port=26257"; + let config = s.parse::().unwrap(); + assert_eq!(Some("pass_user"), config.get_user()); + assert_eq!(Some("postgres"), config.get_dbname()); + assert_eq!( + [ + Host::Tcp("host1".to_string()), + Host::Tcp("host2".to_string()) + ], + config.get_hosts(), + ); + + assert_eq!(["127.0.0.1", "127.0.0.2"], config.get_hostaddrs(),); + + assert_eq!(1, 1); + } + + #[test] + fn test_empty_hostaddrs() { + let s = + "user=pass_user dbname=postgres host=host1,host2,host3 hostaddr=127.0.0.1,,127.0.0.2"; + let config = s.parse::().unwrap(); + assert_eq!(["127.0.0.1", "", "127.0.0.2"], config.get_hostaddrs(),); + } +} diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 97a00c812..c36677234 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -23,6 +23,15 @@ where return Err(Error::config("invalid number of ports".into())); } + if !config.hostaddr.is_empty() && config.hostaddr.len() != config.host.len() { + let msg = format!( + "invalid number of hostaddrs ({}). Possible values: 0 or number of hosts ({})", + config.hostaddr.len(), + config.host.len(), + ); + return Err(Error::config(msg.into())); + } + let mut error = None; for (i, host) in config.host.iter().enumerate() { let port = config @@ -32,18 +41,28 @@ where .copied() .unwrap_or(5432); + // The value of host is always used as the hostname for TLS validation. let hostname = match host { Host::Tcp(host) => host.as_str(), // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter #[cfg(unix)] Host::Unix(_) => "", }; - let tls = tls .make_tls_connect(hostname) .map_err(|e| Error::tls(e.into()))?; - match connect_once(host, port, tls, config).await { + // If both host and hostaddr are specified, the value of hostaddr is used to to establish the TCP connection. + let hostaddr = match host { + Host::Tcp(_hostname) => match config.hostaddr.get(i) { + Some(hostaddr) if hostaddr.is_empty() => Host::Tcp(hostaddr.clone()), + _ => host.clone(), + }, + #[cfg(unix)] + Host::Unix(_v) => host.clone(), + }; + + match connect_once(&hostaddr, port, tls, config).await { Ok((client, connection)) => return Ok((client, connection)), Err(e) => error = Some(e), } From 48874dc5753e33f49508ba986d7f1d7bc74b4a74 Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Sat, 27 Aug 2022 11:40:57 -0700 Subject: [PATCH 231/420] IpAddr + try hostaddr first --- tokio-postgres/src/config.rs | 36 ++++++++++-------- tokio-postgres/src/connect.rs | 61 +++++++++++++++++++------------ tokio-postgres/tests/test/main.rs | 52 ++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 39 deletions(-) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 0c62b5030..34accdbe8 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -13,6 +13,7 @@ use crate::{Client, Connection, Error}; use std::borrow::Cow; #[cfg(unix)] use std::ffi::OsStr; +use std::net::IpAddr; use std::ops::Deref; #[cfg(unix)] use std::os::unix::ffi::OsStrExt; @@ -98,7 +99,9 @@ pub enum Host { /// - or if host specifies an IP address, that value will be used directly. /// Using `hostaddr` allows the application to avoid a host name look-up, which might be important in applications /// with time constraints. However, a host name is required for verify-full SSL certificate verification. -/// Note that `host` is always required regardless of whether `hostaddr` is present. +/// Specifically: +/// * If `hostaddr` is specified without `host`, the value for `hostaddr` gives the server network address. +/// The connection attempt will fail if the authentication method requires a host name; /// * If `host` is specified without `hostaddr`, a host name lookup occurs; /// * If both `host` and `hostaddr` are specified, the value for `hostaddr` gives the server network address. /// The value for `host` is ignored unless the authentication method requires it, @@ -174,7 +177,7 @@ pub struct Config { pub(crate) application_name: Option, pub(crate) ssl_mode: SslMode, pub(crate) host: Vec, - pub(crate) hostaddr: Vec, + pub(crate) hostaddr: Vec, pub(crate) port: Vec, pub(crate) connect_timeout: Option, pub(crate) keepalives: bool, @@ -317,7 +320,7 @@ impl Config { } /// Gets the hostaddrs that have been added to the configuration with `hostaddr`. - pub fn get_hostaddrs(&self) -> &[String] { + pub fn get_hostaddrs(&self) -> &[IpAddr] { self.hostaddr.deref() } @@ -337,8 +340,8 @@ impl Config { /// /// Multiple hostaddrs can be specified by calling this method multiple times, and each will be tried in order. /// There must be either no hostaddrs, or the same number of hostaddrs as hosts. - pub fn hostaddr(&mut self, hostaddr: &str) -> &mut Config { - self.hostaddr.push(hostaddr.to_string()); + pub fn hostaddr(&mut self, hostaddr: IpAddr) -> &mut Config { + self.hostaddr.push(hostaddr); self } @@ -489,7 +492,10 @@ impl Config { } "hostaddr" => { for hostaddr in value.split(',') { - self.hostaddr(hostaddr); + let addr = hostaddr + .parse() + .map_err(|_| Error::config_parse(Box::new(InvalidValue("hostaddr"))))?; + self.hostaddr(addr); } } "port" => { @@ -1016,6 +1022,8 @@ impl<'a> UrlParser<'a> { #[cfg(test)] mod tests { + use std::net::IpAddr; + use crate::{config::Host, Config}; #[test] @@ -1032,16 +1040,14 @@ mod tests { config.get_hosts(), ); - assert_eq!(["127.0.0.1", "127.0.0.2"], config.get_hostaddrs(),); + assert_eq!( + [ + "127.0.0.1".parse::().unwrap(), + "127.0.0.2".parse::().unwrap() + ], + config.get_hostaddrs(), + ); assert_eq!(1, 1); } - - #[test] - fn test_empty_hostaddrs() { - let s = - "user=pass_user dbname=postgres host=host1,host2,host3 hostaddr=127.0.0.1,,127.0.0.2"; - let config = s.parse::().unwrap(); - assert_eq!(["127.0.0.1", "", "127.0.0.2"], config.get_hostaddrs(),); - } } diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index c36677234..ee1dc1c76 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -5,8 +5,8 @@ use crate::connect_socket::connect_socket; use crate::tls::{MakeTlsConnect, TlsConnect}; use crate::{Client, Config, Connection, Error, SimpleQueryMessage, Socket}; use futures_util::{future, pin_mut, Future, FutureExt, Stream}; -use std::io; use std::task::Poll; +use std::{cmp, io}; pub async fn connect( mut tls: T, @@ -15,25 +15,35 @@ pub async fn connect( where T: MakeTlsConnect, { - if config.host.is_empty() { - return Err(Error::config("host missing".into())); + if config.host.is_empty() && config.hostaddr.is_empty() { + return Err(Error::config("both host and hostaddr are missing".into())); } - if config.port.len() > 1 && config.port.len() != config.host.len() { - return Err(Error::config("invalid number of ports".into())); - } - - if !config.hostaddr.is_empty() && config.hostaddr.len() != config.host.len() { + if !config.host.is_empty() + && !config.hostaddr.is_empty() + && config.host.len() != config.hostaddr.len() + { let msg = format!( - "invalid number of hostaddrs ({}). Possible values: 0 or number of hosts ({})", - config.hostaddr.len(), + "number of hosts ({}) is different from number of hostaddrs ({})", config.host.len(), + config.hostaddr.len(), ); return Err(Error::config(msg.into())); } + // At this point, either one of the following two scenarios could happen: + // (1) either config.host or config.hostaddr must be empty; + // (2) if both config.host and config.hostaddr are NOT empty; their lengths must be equal. + let num_hosts = cmp::max(config.host.len(), config.hostaddr.len()); + + if config.port.len() > 1 && config.port.len() != num_hosts { + return Err(Error::config("invalid number of ports".into())); + } + let mut error = None; - for (i, host) in config.host.iter().enumerate() { + for i in 0..num_hosts { + let host = config.host.get(i); + let hostaddr = config.hostaddr.get(i); let port = config .port .get(i) @@ -42,27 +52,30 @@ where .unwrap_or(5432); // The value of host is always used as the hostname for TLS validation. + // postgres doesn't support TLS over unix sockets, so the choice for Host::Unix variant here doesn't matter let hostname = match host { - Host::Tcp(host) => host.as_str(), - // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter - #[cfg(unix)] - Host::Unix(_) => "", + Some(Host::Tcp(host)) => host.as_str(), + _ => "", }; let tls = tls .make_tls_connect(hostname) .map_err(|e| Error::tls(e.into()))?; - // If both host and hostaddr are specified, the value of hostaddr is used to to establish the TCP connection. - let hostaddr = match host { - Host::Tcp(_hostname) => match config.hostaddr.get(i) { - Some(hostaddr) if hostaddr.is_empty() => Host::Tcp(hostaddr.clone()), - _ => host.clone(), - }, - #[cfg(unix)] - Host::Unix(_v) => host.clone(), + // Try to use the value of hostaddr to establish the TCP connection, + // fallback to host if hostaddr is not present. + let addr = match hostaddr { + Some(ipaddr) => Host::Tcp(ipaddr.to_string()), + None => { + if let Some(host) = host { + host.clone() + } else { + // This is unreachable. + return Err(Error::config("both host and hostaddr are empty".into())); + } + } }; - match connect_once(&hostaddr, port, tls, config).await { + match connect_once(&addr, port, tls, config).await { Ok((client, connection)) => return Ok((client, connection)), Err(e) => error = Some(e), } diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index 0ab4a7bab..387c90d7c 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -147,6 +147,58 @@ async fn scram_password_ok() { connect("user=scram_user password=password dbname=postgres").await; } +#[tokio::test] +async fn host_only_ok() { + let _ = tokio_postgres::connect( + "host=localhost port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_only_ok() { + let _ = tokio_postgres::connect( + "hostaddr=127.0.0.1 port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_and_host_ok() { + let _ = tokio_postgres::connect( + "hostaddr=127.0.0.1 host=localhost port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_host_mismatch() { + let _ = tokio_postgres::connect( + "hostaddr=127.0.0.1,127.0.0.2 host=localhost port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .err() + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_host_both_missing() { + let _ = tokio_postgres::connect( + "port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .err() + .unwrap(); +} + #[tokio::test] async fn pipelined_prepare() { let client = connect("user=postgres").await; From d97bed635ef3fe21a3d9dbef0945e57ab2baf8ba Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Sat, 27 Aug 2022 11:55:11 -0700 Subject: [PATCH 232/420] also update postgres --- postgres/src/config.rs | 33 +++++++++++++++++++++++++++++++++ tokio-postgres/src/config.rs | 1 + 2 files changed, 34 insertions(+) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index b541ec846..a754ff91f 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -6,6 +6,7 @@ use crate::connection::Connection; use crate::Client; use log::info; use std::fmt; +use std::net::IpAddr; use std::path::Path; use std::str::FromStr; use std::sync::Arc; @@ -39,6 +40,19 @@ 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. +/// * `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, +/// - or if host specifies an IP address, that value will be used directly. +/// Using `hostaddr` allows the application to avoid a host name look-up, which might be important in applications +/// with time constraints. However, a host name is required for verify-full SSL certificate verification. +/// Specifically: +/// * If `hostaddr` is specified without `host`, the value for `hostaddr` gives the server network address. +/// The connection attempt will fail if the authentication method requires a host name; +/// * If `host` is specified without `hostaddr`, a host name lookup occurs; +/// * If both `host` and `hostaddr` are specified, the value for `hostaddr` gives the server network address. +/// The value for `host` is ignored unless the authentication method requires it, +/// in which case it will be used as the host name. /// * `port` - The port to connect to. Multiple ports can be specified, separated by commas. The number of ports must be /// either 1, in which case it will be used for all hosts, or the same as the number of hosts. Defaults to 5432 if /// omitted or the empty string. @@ -67,6 +81,10 @@ use tokio_postgres::{Error, Socket}; /// ``` /// /// ```not_rust +/// host=host1,host2,host3 port=1234,,5678 hostaddr=127.0.0.1,127.0.0.2,127.0.0.3 user=postgres target_session_attrs=read-write +/// ``` +/// +/// ```not_rust /// host=host1,host2,host3 port=1234,,5678 user=postgres target_session_attrs=read-write /// ``` /// @@ -204,6 +222,7 @@ impl Config { /// /// Multiple hosts can be specified by calling this method multiple times, and each will be tried in order. On Unix /// systems, a host starting with a `/` is interpreted as a path to a directory containing Unix domain sockets. + /// There must be either no hosts, or the same number of hosts as hostaddrs. pub fn host(&mut self, host: &str) -> &mut Config { self.config.host(host); self @@ -214,6 +233,11 @@ impl Config { self.config.get_hosts() } + /// Gets the hostaddrs that have been added to the configuration with `hostaddr`. + pub fn get_hostaddrs(&self) -> &[IpAddr] { + self.config.get_hostaddrs() + } + /// Adds a Unix socket host to the configuration. /// /// Unlike `host`, this method allows non-UTF8 paths. @@ -226,6 +250,15 @@ impl Config { self } + /// Adds a hostaddr to the configuration. + /// + /// Multiple hostaddrs can be specified by calling this method multiple times, and each will be tried in order. + /// There must be either no hostaddrs, or the same number of hostaddrs as hosts. + pub fn hostaddr(&mut self, hostaddr: IpAddr) -> &mut Config { + self.config.hostaddr(hostaddr); + self + } + /// Adds a port to the configuration. /// /// Multiple ports can be specified by calling this method multiple times. There must either be no ports, in which diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 34accdbe8..923da2985 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -302,6 +302,7 @@ impl Config { /// /// Multiple hosts can be specified by calling this method multiple times, and each will be tried in order. On Unix /// systems, a host starting with a `/` is interpreted as a path to a directory containing Unix domain sockets. + /// There must be either no hosts, or the same number of hosts as hostaddrs. pub fn host(&mut self, host: &str) -> &mut Config { #[cfg(unix)] { From 1a9c1d4ff3e25b7bef01f05c3e396b2eec1564d9 Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Sat, 27 Aug 2022 11:55:47 -0700 Subject: [PATCH 233/420] fmt --- postgres/src/config.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index a754ff91f..921566b66 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -83,7 +83,7 @@ use tokio_postgres::{Error, Socket}; /// ```not_rust /// host=host1,host2,host3 port=1234,,5678 hostaddr=127.0.0.1,127.0.0.2,127.0.0.3 user=postgres target_session_attrs=read-write /// ``` -/// +/// /// ```not_rust /// host=host1,host2,host3 port=1234,,5678 user=postgres target_session_attrs=read-write /// ``` @@ -236,7 +236,7 @@ impl Config { /// Gets the hostaddrs that have been added to the configuration with `hostaddr`. pub fn get_hostaddrs(&self) -> &[IpAddr] { self.config.get_hostaddrs() - } + } /// Adds a Unix socket host to the configuration. /// From 58149dacf6f4633a3c2b24cda442623bd2abb08d Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Sun, 28 Aug 2022 12:09:53 -0700 Subject: [PATCH 234/420] explicitly handle host being None --- tokio-postgres/src/connect.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index ee1dc1c76..63574516c 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -51,14 +51,17 @@ where .copied() .unwrap_or(5432); - // The value of host is always used as the hostname for TLS validation. - // postgres doesn't support TLS over unix sockets, so the choice for Host::Unix variant here doesn't matter + // The value of host is used as the hostname for TLS validation, + // if it's not present, use the value of hostaddr. let hostname = match host { - Some(Host::Tcp(host)) => host.as_str(), - _ => "", + Some(Host::Tcp(host)) => host.clone(), + // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter Some() + #[cfg(unix)] + Some(Host::Unix(_)) => "".to_string(), + None => hostaddr.map_or("".to_string(), |ipaddr| ipaddr.to_string()), }; let tls = tls - .make_tls_connect(hostname) + .make_tls_connect(&hostname) .map_err(|e| Error::tls(e.into()))?; // Try to use the value of hostaddr to establish the TCP connection, From 7a648ad0cb911cb9144c0db441399f3189d28b3b Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Sun, 28 Aug 2022 12:18:36 -0700 Subject: [PATCH 235/420] add negative test --- tokio-postgres/src/config.rs | 6 ++++++ tokio-postgres/src/connect.rs | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 923da2985..e5bed8ddf 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -1051,4 +1051,10 @@ mod tests { assert_eq!(1, 1); } + + #[test] + fn test_invalid_hostaddr_parsing() { + let s = "user=pass_user dbname=postgres host=host1 hostaddr=127.0.0 port=26257"; + s.parse::().err().unwrap(); + } } diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 63574516c..888f9cf8a 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -55,7 +55,7 @@ where // if it's not present, use the value of hostaddr. let hostname = match host { Some(Host::Tcp(host)) => host.clone(), - // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter Some() + // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter #[cfg(unix)] Some(Host::Unix(_)) => "".to_string(), None => hostaddr.map_or("".to_string(), |ipaddr| ipaddr.to_string()), From a70a7c36c74bfeaf1e171dc2572fddd30d182179 Mon Sep 17 00:00:00 2001 From: Trung Dinh Date: Tue, 30 Aug 2022 22:10:19 -0700 Subject: [PATCH 236/420] move test to runtime --- tokio-postgres/tests/test/main.rs | 52 ---------------------------- tokio-postgres/tests/test/runtime.rs | 52 ++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index 387c90d7c..0ab4a7bab 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -147,58 +147,6 @@ async fn scram_password_ok() { connect("user=scram_user password=password dbname=postgres").await; } -#[tokio::test] -async fn host_only_ok() { - let _ = tokio_postgres::connect( - "host=localhost port=5433 user=pass_user dbname=postgres password=password", - NoTls, - ) - .await - .unwrap(); -} - -#[tokio::test] -async fn hostaddr_only_ok() { - let _ = tokio_postgres::connect( - "hostaddr=127.0.0.1 port=5433 user=pass_user dbname=postgres password=password", - NoTls, - ) - .await - .unwrap(); -} - -#[tokio::test] -async fn hostaddr_and_host_ok() { - let _ = tokio_postgres::connect( - "hostaddr=127.0.0.1 host=localhost port=5433 user=pass_user dbname=postgres password=password", - NoTls, - ) - .await - .unwrap(); -} - -#[tokio::test] -async fn hostaddr_host_mismatch() { - let _ = tokio_postgres::connect( - "hostaddr=127.0.0.1,127.0.0.2 host=localhost port=5433 user=pass_user dbname=postgres password=password", - NoTls, - ) - .await - .err() - .unwrap(); -} - -#[tokio::test] -async fn hostaddr_host_both_missing() { - let _ = tokio_postgres::connect( - "port=5433 user=pass_user dbname=postgres password=password", - NoTls, - ) - .await - .err() - .unwrap(); -} - #[tokio::test] async fn pipelined_prepare() { let client = connect("user=postgres").await; diff --git a/tokio-postgres/tests/test/runtime.rs b/tokio-postgres/tests/test/runtime.rs index 67b4ead8a..86c1f0701 100644 --- a/tokio-postgres/tests/test/runtime.rs +++ b/tokio-postgres/tests/test/runtime.rs @@ -66,6 +66,58 @@ async fn target_session_attrs_err() { .unwrap(); } +#[tokio::test] +async fn host_only_ok() { + let _ = tokio_postgres::connect( + "host=localhost port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_only_ok() { + let _ = tokio_postgres::connect( + "hostaddr=127.0.0.1 port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_and_host_ok() { + let _ = tokio_postgres::connect( + "hostaddr=127.0.0.1 host=localhost port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_host_mismatch() { + let _ = tokio_postgres::connect( + "hostaddr=127.0.0.1,127.0.0.2 host=localhost port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .err() + .unwrap(); +} + +#[tokio::test] +async fn hostaddr_host_both_missing() { + let _ = tokio_postgres::connect( + "port=5433 user=pass_user dbname=postgres password=password", + NoTls, + ) + .await + .err() + .unwrap(); +} + #[tokio::test] async fn cancel_query() { let client = connect("host=localhost port=5433 user=postgres").await; From d368475b50880b920ffbd73b7d6398b2171db53f Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Fri, 30 Dec 2022 13:47:41 +0200 Subject: [PATCH 237/420] Add flush() to front-end messages The PostgreSQL wire protocol has a "Flush" message, which can be used by the clients for long-lived connections. Add a flush() helper for it. --- postgres-protocol/src/message/frontend.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/postgres-protocol/src/message/frontend.rs b/postgres-protocol/src/message/frontend.rs index 5d0a8ff8c..600f7da48 100644 --- a/postgres-protocol/src/message/frontend.rs +++ b/postgres-protocol/src/message/frontend.rs @@ -271,6 +271,12 @@ where }) } +#[inline] +pub fn flush(buf: &mut BytesMut) { + buf.put_u8(b'H'); + write_body(buf, |_| Ok::<(), io::Error>(())).unwrap(); +} + #[inline] pub fn sync(buf: &mut BytesMut) { buf.put_u8(b'S'); From 8ab8f1a5552545986ba660cf2ad45ae2c8e54160 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 30 Dec 2022 08:43:24 -0500 Subject: [PATCH 238/420] Clippy --- postgres-protocol/src/message/backend.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres-protocol/src/message/backend.rs b/postgres-protocol/src/message/backend.rs index 3f5374d64..e0eacbea0 100644 --- a/postgres-protocol/src/message/backend.rs +++ b/postgres-protocol/src/message/backend.rs @@ -582,7 +582,7 @@ impl<'a> FallibleIterator for DataRowRanges<'a> { )); } let base = self.len - self.buf.len(); - self.buf = &self.buf[len as usize..]; + self.buf = &self.buf[len..]; Ok(Some(Some(base..base + len))) } } From 0c056148d0c484def905b16b539fb845e31541d4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2023 20:33:06 -0500 Subject: [PATCH 239/420] Clarify poll_message docs Closes #975 --- tokio-postgres/src/connection.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tokio-postgres/src/connection.rs b/tokio-postgres/src/connection.rs index 30be4e834..414335955 100644 --- a/tokio-postgres/src/connection.rs +++ b/tokio-postgres/src/connection.rs @@ -302,6 +302,9 @@ where /// /// The server can send notices as well as notifications asynchronously to the client. Applications that wish to /// examine those messages should use this method to drive the connection rather than its `Future` implementation. + /// + /// Return values of `None` or `Some(Err(_))` are "terminal"; callers should not invoke this method again after + /// receiving one of those values. pub fn poll_message( &mut self, cx: &mut Context<'_>, From e38e435665af8dbd55e7d803f019405653f99205 Mon Sep 17 00:00:00 2001 From: Ari Breitkreuz Date: Sun, 8 Jan 2023 12:21:42 +0100 Subject: [PATCH 240/420] add batch_execute to generic client --- tokio-postgres/src/generic_client.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tokio-postgres/src/generic_client.rs b/tokio-postgres/src/generic_client.rs index b2a907558..f05a422cc 100644 --- a/tokio-postgres/src/generic_client.rs +++ b/tokio-postgres/src/generic_client.rs @@ -69,6 +69,10 @@ pub trait GenericClient: private::Sealed { /// Like `Client::transaction`. async fn transaction(&mut self) -> Result, Error>; + /// Like `Client::batch_execute`. + async fn batch_execute(&self, query: &str) -> Result<(), Error>; + + /// Returns a reference to the underlying `Client`. fn client(&self) -> &Client; } @@ -149,6 +153,10 @@ impl GenericClient for Client { self.transaction().await } + async fn batch_execute(&self, query: &str) -> Result<(), Error> { + self.batch_execute(query).await + } + fn client(&self) -> &Client { self } @@ -232,6 +240,10 @@ impl GenericClient for Transaction<'_> { self.transaction().await } + async fn batch_execute(&self, query: &str) -> Result<(), Error> { + self.batch_execute(query).await + } + fn client(&self) -> &Client { self.client() } From 383fd50f75a0314cde53b46ec9aafcba870fadbe Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 8 Jan 2023 08:32:00 -0500 Subject: [PATCH 241/420] Update tokio-postgres/src/generic_client.rs --- tokio-postgres/src/generic_client.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tokio-postgres/src/generic_client.rs b/tokio-postgres/src/generic_client.rs index f05a422cc..50cff9712 100644 --- a/tokio-postgres/src/generic_client.rs +++ b/tokio-postgres/src/generic_client.rs @@ -72,7 +72,6 @@ pub trait GenericClient: private::Sealed { /// Like `Client::batch_execute`. async fn batch_execute(&self, query: &str) -> Result<(), Error>; - /// Returns a reference to the underlying `Client`. fn client(&self) -> &Client; } From c5cb28bcaf2f4031a88c044b40750a65391d8be8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jan 2023 13:06:33 +0000 Subject: [PATCH 242/420] Update base64 requirement from 0.20 to 0.21 Updates the requirements on [base64](https://github.com/marshallpierce/rust-base64) to permit the latest version. - [Release notes](https://github.com/marshallpierce/rust-base64/releases) - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.20.0...v0.21.0) --- updated-dependencies: - dependency-name: base64 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 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 2a72cc60c..922e92313 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/sfackler/rust-postgres" readme = "../README.md" [dependencies] -base64 = "0.20" +base64 = "0.21" byteorder = "1.0" bytes = "1.0" fallible-iterator = "0.2" From 10bf27128dc4444c650bb371c835a9b87cea4102 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 9 Jan 2023 20:41:16 -0500 Subject: [PATCH 243/420] fix build --- postgres-protocol/src/authentication/sasl.rs | 16 ++++++++++++---- postgres-protocol/src/password/mod.rs | 8 +++++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/postgres-protocol/src/authentication/sasl.rs b/postgres-protocol/src/authentication/sasl.rs index ea2f55cad..2352a66c4 100644 --- a/postgres-protocol/src/authentication/sasl.rs +++ b/postgres-protocol/src/authentication/sasl.rs @@ -1,5 +1,8 @@ //! SASL-based authentication support. +use base64::display::Base64Display; +use base64::engine::general_purpose::STANDARD; +use base64::Engine; use hmac::{Hmac, Mac}; use rand::{self, Rng}; use sha2::digest::FixedOutput; @@ -189,7 +192,7 @@ impl ScramSha256 { return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid nonce")); } - let salt = match base64::decode(parsed.salt) { + let salt = match STANDARD.decode(parsed.salt) { Ok(salt) => salt, Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidInput, e)), }; @@ -208,7 +211,7 @@ impl ScramSha256 { let mut cbind_input = vec![]; cbind_input.extend(channel_binding.gs2_header().as_bytes()); cbind_input.extend(channel_binding.cbind_data()); - let cbind_input = base64::encode(&cbind_input); + let cbind_input = STANDARD.encode(&cbind_input); self.message.clear(); write!(&mut self.message, "c={},r={}", cbind_input, parsed.nonce).unwrap(); @@ -225,7 +228,12 @@ impl ScramSha256 { *proof ^= signature; } - write!(&mut self.message, ",p={}", base64::encode(&*client_proof)).unwrap(); + write!( + &mut self.message, + ",p={}", + Base64Display::new(&client_proof, &STANDARD) + ) + .unwrap(); self.state = State::Finish { salted_password, @@ -262,7 +270,7 @@ impl ScramSha256 { ServerFinalMessage::Verifier(verifier) => verifier, }; - let verifier = match base64::decode(verifier) { + let verifier = match STANDARD.decode(verifier) { Ok(verifier) => verifier, Err(e) => return Err(io::Error::new(io::ErrorKind::InvalidInput, e)), }; diff --git a/postgres-protocol/src/password/mod.rs b/postgres-protocol/src/password/mod.rs index a60687bbe..f03bb811d 100644 --- a/postgres-protocol/src/password/mod.rs +++ b/postgres-protocol/src/password/mod.rs @@ -7,6 +7,8 @@ //! end up in logs pg_stat displays, etc. use crate::authentication::sasl; +use base64::display::Base64Display; +use base64::engine::general_purpose::STANDARD; use hmac::{Hmac, Mac}; use md5::Md5; use rand::RngCore; @@ -80,9 +82,9 @@ pub(crate) fn scram_sha_256_salt(password: &[u8], salt: [u8; SCRAM_DEFAULT_SALT_ format!( "SCRAM-SHA-256${}:{}${}:{}", SCRAM_DEFAULT_ITERATIONS, - base64::encode(salt), - base64::encode(stored_key), - base64::encode(server_key) + Base64Display::new(&salt, &STANDARD), + Base64Display::new(&stored_key, &STANDARD), + Base64Display::new(&server_key, &STANDARD) ) } From cf77dc06e69a08327f2656fd8e895038d66da12e Mon Sep 17 00:00:00 2001 From: Tom Parker-Shemilt Date: Tue, 10 Jan 2023 11:47:53 +0000 Subject: [PATCH 244/420] futures-util <0.3.14 doesn't have Stream --- postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index bd7c297f3..e3a8663f2 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -38,7 +38,7 @@ with-time-0_3 = ["tokio-postgres/with-time-0_3"] [dependencies] bytes = "1.0" fallible-iterator = "0.2" -futures-util = { version = "0.3", features = ["sink"] } +futures-util = { version = "0.3.14", features = ["sink"] } tokio-postgres = { version = "0.7.7", path = "../tokio-postgres" } tokio = { version = "1.0", features = ["rt", "time"] } From 205af89aafb8fec5e8a75599e0401d5797932f13 Mon Sep 17 00:00:00 2001 From: Alex Chi Date: Sun, 15 Jan 2023 21:16:56 -0500 Subject: [PATCH 245/420] feat: add `rows_affected` to RowStream Signed-off-by: Alex Chi --- tokio-postgres/src/copy_in.rs | 10 ++----- tokio-postgres/src/query.rs | 43 +++++++++++++++++++++--------- tokio-postgres/src/simple_query.rs | 10 ++----- 3 files changed, 35 insertions(+), 28 deletions(-) diff --git a/tokio-postgres/src/copy_in.rs b/tokio-postgres/src/copy_in.rs index de1da933b..59e31fea6 100644 --- a/tokio-postgres/src/copy_in.rs +++ b/tokio-postgres/src/copy_in.rs @@ -1,6 +1,7 @@ use crate::client::{InnerClient, Responses}; use crate::codec::FrontendMessage; use crate::connection::RequestMessages; +use crate::query::extract_row_affected; use crate::{query, slice_iter, Error, Statement}; use bytes::{Buf, BufMut, BytesMut}; use futures_channel::mpsc; @@ -110,14 +111,7 @@ where let this = self.as_mut().project(); match ready!(this.responses.poll_next(cx))? { Message::CommandComplete(body) => { - let rows = body - .tag() - .map_err(Error::parse)? - .rsplit(' ') - .next() - .unwrap() - .parse() - .unwrap_or(0); + let rows = extract_row_affected(&body)?; return Poll::Ready(Ok(rows)); } _ => return Poll::Ready(Err(Error::unexpected_message())), diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index 71db8769a..72e92ccda 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -7,7 +7,7 @@ use bytes::{Bytes, BytesMut}; use futures_util::{ready, Stream}; use log::{debug, log_enabled, Level}; use pin_project_lite::pin_project; -use postgres_protocol::message::backend::Message; +use postgres_protocol::message::backend::{CommandCompleteBody, Message}; use postgres_protocol::message::frontend; use std::fmt; use std::marker::PhantomPinned; @@ -52,6 +52,7 @@ where Ok(RowStream { statement, responses, + rows_affected: None, _p: PhantomPinned, }) } @@ -72,10 +73,24 @@ pub async fn query_portal( Ok(RowStream { statement: portal.statement().clone(), responses, + rows_affected: None, _p: PhantomPinned, }) } +/// Extract the number of rows affected from [`CommandCompleteBody`]. +pub fn extract_row_affected(body: &CommandCompleteBody) -> Result { + let rows = body + .tag() + .map_err(Error::parse)? + .rsplit(' ') + .next() + .unwrap() + .parse() + .unwrap_or(0); + Ok(rows) +} + pub async fn execute( client: &InnerClient, statement: Statement, @@ -104,14 +119,7 @@ where match responses.next().await? { Message::DataRow(_) => {} Message::CommandComplete(body) => { - rows = body - .tag() - .map_err(Error::parse)? - .rsplit(' ') - .next() - .unwrap() - .parse() - .unwrap_or(0); + rows = extract_row_affected(&body)?; } Message::EmptyQueryResponse => rows = 0, Message::ReadyForQuery(_) => return Ok(rows), @@ -202,6 +210,7 @@ pin_project! { pub struct RowStream { statement: Statement, responses: Responses, + rows_affected: Option, #[pin] _p: PhantomPinned, } @@ -217,12 +226,22 @@ impl Stream for RowStream { Message::DataRow(body) => { return Poll::Ready(Some(Ok(Row::new(this.statement.clone(), body)?))) } - Message::EmptyQueryResponse - | Message::CommandComplete(_) - | Message::PortalSuspended => {} + Message::CommandComplete(body) => { + *this.rows_affected = Some(extract_row_affected(&body)?); + } + Message::EmptyQueryResponse | Message::PortalSuspended => {} Message::ReadyForQuery(_) => return Poll::Ready(None), _ => return Poll::Ready(Some(Err(Error::unexpected_message()))), } } } } + +impl RowStream { + /// Returns the number of rows affected by the query. + /// + /// This will be `None` if the information is not available yet. + pub fn rows_affected(&self) -> Option { + self.rows_affected + } +} diff --git a/tokio-postgres/src/simple_query.rs b/tokio-postgres/src/simple_query.rs index 7c266e409..bcc6d928b 100644 --- a/tokio-postgres/src/simple_query.rs +++ b/tokio-postgres/src/simple_query.rs @@ -1,6 +1,7 @@ use crate::client::{InnerClient, Responses}; use crate::codec::FrontendMessage; use crate::connection::RequestMessages; +use crate::query::extract_row_affected; use crate::{Error, SimpleQueryMessage, SimpleQueryRow}; use bytes::Bytes; use fallible_iterator::FallibleIterator; @@ -87,14 +88,7 @@ impl Stream for SimpleQueryStream { loop { match ready!(this.responses.poll_next(cx)?) { Message::CommandComplete(body) => { - let rows = body - .tag() - .map_err(Error::parse)? - .rsplit(' ') - .next() - .unwrap() - .parse() - .unwrap_or(0); + let rows = extract_row_affected(&body)?; return Poll::Ready(Some(Ok(SimpleQueryMessage::CommandComplete(rows)))); } Message::EmptyQueryResponse => { From b1842390c3946947ed43bce998d3480b699786ec Mon Sep 17 00:00:00 2001 From: Alex Chi Date: Mon, 16 Jan 2023 22:54:20 -0500 Subject: [PATCH 246/420] update comments Signed-off-by: Alex Chi --- 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 72e92ccda..12176353b 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -240,7 +240,7 @@ impl Stream for RowStream { impl RowStream { /// Returns the number of rows affected by the query. /// - /// This will be `None` if the information is not available yet. + /// This function will return `None` until the stream has been exhausted. pub fn rows_affected(&self) -> Option { self.rows_affected } From eb086d30a30bb402daddd29cbd53bfcfc9c00a7f Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Fri, 24 Feb 2023 09:56:05 +0800 Subject: [PATCH 247/420] export Bytes type through DataRowBody::storage_bytes method. --- postgres-protocol/src/message/backend.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/postgres-protocol/src/message/backend.rs b/postgres-protocol/src/message/backend.rs index e0eacbea0..2b245101e 100644 --- a/postgres-protocol/src/message/backend.rs +++ b/postgres-protocol/src/message/backend.rs @@ -544,6 +544,11 @@ impl DataRowBody { pub fn buffer(&self) -> &[u8] { &self.storage } + + #[inline] + pub fn storage_bytes(&self) -> &Bytes { + &self.storage + } } pub struct DataRowRanges<'a> { From 842eacefc82e1e2d8ef69d60eb14c5e421c5298b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 25 Feb 2023 10:10:04 -0500 Subject: [PATCH 248/420] fix ci --- .github/workflows/ci.yml | 2 +- postgres-derive-test/src/lib.rs | 4 ++-- postgres-protocol/src/authentication/sasl.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8d17f4d6b..92afbb0c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: - run: docker compose up -d - uses: sfackler/actions/rustup@master with: - version: 1.62.0 + version: 1.63.0 - run: echo "::set-output name=version::$(rustc --version)" id: rust-version - uses: actions/cache@v1 diff --git a/postgres-derive-test/src/lib.rs b/postgres-derive-test/src/lib.rs index d1478ac4c..f0534f32c 100644 --- a/postgres-derive-test/src/lib.rs +++ b/postgres-derive-test/src/lib.rs @@ -14,7 +14,7 @@ where T: PartialEq + FromSqlOwned + ToSql + Sync, S: fmt::Display, { - for &(ref val, ref repr) in checks.iter() { + for (val, repr) in checks.iter() { let stmt = conn .prepare(&format!("SELECT {}::{}", *repr, sql_type)) .unwrap(); @@ -38,7 +38,7 @@ pub fn test_type_asymmetric( S: fmt::Display, C: Fn(&T, &F) -> bool, { - for &(ref val, ref repr) in checks.iter() { + for (val, repr) in checks.iter() { let stmt = conn .prepare(&format!("SELECT {}::{}", *repr, sql_type)) .unwrap(); diff --git a/postgres-protocol/src/authentication/sasl.rs b/postgres-protocol/src/authentication/sasl.rs index 2352a66c4..4a77507e9 100644 --- a/postgres-protocol/src/authentication/sasl.rs +++ b/postgres-protocol/src/authentication/sasl.rs @@ -359,7 +359,7 @@ impl<'a> Parser<'a> { } fn posit_number(&mut self) -> io::Result { - let n = self.take_while(|c| matches!(c, '0'..='9'))?; + let n = self.take_while(|c| c.is_ascii_digit())?; n.parse() .map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e)) } From 63c09eb083ac3a2c3e39c798cda49d35938fefc4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 25 Feb 2023 10:18:38 -0500 Subject: [PATCH 249/420] fix workflow deprecations --- .github/workflows/ci.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92afbb0c8..f81bdee46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ jobs: name: rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: sfackler/actions/rustup@master - uses: sfackler/actions/rustfmt@master @@ -25,23 +25,23 @@ jobs: name: clippy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: sfackler/actions/rustup@master - - run: echo "::set-output name=version::$(rustc --version)" + - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/index key: index-${{ runner.os }}-${{ github.run_number }} restore-keys: | index-${{ runner.os }}- - run: cargo generate-lockfile - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/cache key: registry-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - run: cargo fetch - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: target key: clippy-target-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}y @@ -51,26 +51,26 @@ jobs: name: test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - run: docker compose up -d - uses: sfackler/actions/rustup@master with: version: 1.63.0 - - run: echo "::set-output name=version::$(rustc --version)" + - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/index key: index-${{ runner.os }}-${{ github.run_number }} restore-keys: | index-${{ runner.os }}- - run: cargo generate-lockfile - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: ~/.cargo/registry/cache key: registry-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} - run: cargo fetch - - uses: actions/cache@v1 + - uses: actions/cache@v3 with: path: target key: test-target-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}y From 7c7c80dcaab7051bce4f31c36abe78c139f08050 Mon Sep 17 00:00:00 2001 From: Benjamin Swart Date: Thu, 23 Feb 2023 18:32:15 +0100 Subject: [PATCH 250/420] Make incorrect number of paramaters an error --- postgres/src/client.rs | 20 -------------------- tokio-postgres/src/client.rs | 32 -------------------------------- tokio-postgres/src/error/mod.rs | 8 ++++++++ tokio-postgres/src/query.rs | 9 +++------ 4 files changed, 11 insertions(+), 58 deletions(-) diff --git a/postgres/src/client.rs b/postgres/src/client.rs index 29cac840d..c8e14cf81 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -57,10 +57,6 @@ impl Client { /// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front /// with the `prepare` method. /// - /// # Panics - /// - /// Panics if the number of parameters provided does not match the number expected. - /// /// # Example /// /// ```no_run @@ -96,10 +92,6 @@ impl Client { /// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front /// with the `prepare` method. /// - /// # Panics - /// - /// Panics if the number of parameters provided does not match the number expected. - /// /// # Examples /// /// ```no_run @@ -134,10 +126,6 @@ impl Client { /// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front /// with the `prepare` method. /// - /// # Panics - /// - /// Panics if the number of parameters provided does not match the number expected. - /// /// # Examples /// /// ```no_run @@ -172,10 +160,6 @@ impl Client { /// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front /// with the `prepare` method. /// - /// # Panics - /// - /// Panics if the number of parameters provided does not match the number expected. - /// /// # Examples /// /// ```no_run @@ -213,10 +197,6 @@ impl Client { /// It takes an iterator of parameters rather than a slice, and returns an iterator of rows rather than collecting /// them into an array. /// - /// # Panics - /// - /// Panics if the number of parameters provided does not match the number expected. - /// /// # Examples /// /// ```no_run diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index ad5aa2866..5d0d2c536 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -230,10 +230,6 @@ impl Client { /// The `statement` argument can either be a `Statement`, or a raw query string. If the same statement will be /// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front /// with the `prepare` method. - /// - /// # Panics - /// - /// Panics if the number of parameters provided does not match the number expected. pub async fn query( &self, statement: &T, @@ -258,10 +254,6 @@ impl Client { /// The `statement` argument can either be a `Statement`, or a raw query string. If the same statement will be /// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front /// with the `prepare` method. - /// - /// # Panics - /// - /// Panics if the number of parameters provided does not match the number expected. pub async fn query_one( &self, statement: &T, @@ -295,10 +287,6 @@ impl Client { /// The `statement` argument can either be a `Statement`, or a raw query string. If the same statement will be /// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front /// with the `prepare` method. - /// - /// # Panics - /// - /// Panics if the number of parameters provided does not match the number expected. pub async fn query_opt( &self, statement: &T, @@ -331,10 +319,6 @@ impl Client { /// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front /// with the `prepare` method. /// - /// # Panics - /// - /// Panics if the number of parameters provided does not match the number expected. - /// /// [`query`]: #method.query /// /// # Examples @@ -382,10 +366,6 @@ impl Client { /// with the `prepare` method. /// /// If the statement does not modify any rows (e.g. `SELECT`), 0 is returned. - /// - /// # Panics - /// - /// Panics if the number of parameters provided does not match the number expected. pub async fn execute( &self, statement: &T, @@ -406,10 +386,6 @@ impl Client { /// repeatedly executed (perhaps with different query parameters), consider preparing the statement up front /// with the `prepare` method. /// - /// # Panics - /// - /// Panics if the number of parameters provided does not match the number expected. - /// /// [`execute`]: #method.execute pub async fn execute_raw(&self, statement: &T, params: I) -> Result where @@ -426,10 +402,6 @@ impl Client { /// /// PostgreSQL does not support parameters in `COPY` statements, so this method does not take any. The copy *must* /// be explicitly completed via the `Sink::close` or `finish` methods. If it is not, the copy will be aborted. - /// - /// # Panics - /// - /// Panics if the statement contains parameters. pub async fn copy_in(&self, statement: &T) -> Result, Error> where T: ?Sized + ToStatement, @@ -442,10 +414,6 @@ impl Client { /// Executes a `COPY TO STDOUT` statement, returning a stream of the resulting data. /// /// PostgreSQL does not support parameters in `COPY` statements, so this method does not take any. - /// - /// # Panics - /// - /// Panics if the statement contains parameters. pub async fn copy_out(&self, statement: &T) -> Result where T: ?Sized + ToStatement, diff --git a/tokio-postgres/src/error/mod.rs b/tokio-postgres/src/error/mod.rs index 47a31e793..f1e2644c6 100644 --- a/tokio-postgres/src/error/mod.rs +++ b/tokio-postgres/src/error/mod.rs @@ -344,6 +344,7 @@ enum Kind { ToSql(usize), FromSql(usize), Column(String), + Parameters(usize, usize), Closed, Db, Parse, @@ -383,6 +384,9 @@ impl fmt::Display for Error { Kind::ToSql(idx) => write!(fmt, "error serializing parameter {}", idx)?, Kind::FromSql(idx) => write!(fmt, "error deserializing column {}", idx)?, Kind::Column(column) => write!(fmt, "invalid column `{}`", column)?, + Kind::Parameters(real, expected) => { + write!(fmt, "expected {expected} parameters but got {real}")? + } Kind::Closed => fmt.write_str("connection closed")?, Kind::Db => fmt.write_str("db error")?, Kind::Parse => fmt.write_str("error parsing response from server")?, @@ -474,6 +478,10 @@ impl Error { Error::new(Kind::Column(column), None) } + pub(crate) fn parameters(real: usize, expected: usize) -> Error { + Error::new(Kind::Parameters(real, expected), None) + } + pub(crate) fn tls(e: Box) -> Error { Error::new(Kind::Tls, Some(e)) } diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index 12176353b..e6e1d00a8 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -167,12 +167,9 @@ where let param_types = statement.params(); let params = params.into_iter(); - assert!( - param_types.len() == params.len(), - "expected {} parameters but got {}", - param_types.len(), - params.len() - ); + if param_types.len() != params.len() { + return Err(Error::parameters(params.len(), param_types.len())); + } let (param_formats, params): (Vec<_>, Vec<_>) = params .zip(param_types.iter()) From 7cd7b187a5cb990ceb0ea9531cd3345b1e2799c3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 26 Feb 2023 16:44:25 -0500 Subject: [PATCH 251/420] Rename accessor --- postgres-protocol/src/message/backend.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres-protocol/src/message/backend.rs b/postgres-protocol/src/message/backend.rs index 2b245101e..1b5be1098 100644 --- a/postgres-protocol/src/message/backend.rs +++ b/postgres-protocol/src/message/backend.rs @@ -546,7 +546,7 @@ impl DataRowBody { } #[inline] - pub fn storage_bytes(&self) -> &Bytes { + pub fn buffer_bytes(&self) -> &Bytes { &self.storage } } From 1e1f90786d5df3ac9701b667f9a57bf783357455 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 14:06:03 +0000 Subject: [PATCH 252/420] Update syn requirement from 1.0 to 2.0 Updates the requirements on [syn](https://github.com/dtolnay/syn) to permit the latest version. - [Release notes](https://github.com/dtolnay/syn/releases) - [Commits](https://github.com/dtolnay/syn/compare/1.0.0...2.0.3) --- updated-dependencies: - dependency-name: syn dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- postgres-derive/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres-derive/Cargo.toml b/postgres-derive/Cargo.toml index 22b50b707..8470bc8a9 100644 --- a/postgres-derive/Cargo.toml +++ b/postgres-derive/Cargo.toml @@ -12,6 +12,6 @@ proc-macro = true test = false [dependencies] -syn = "1.0" +syn = "2.0" proc-macro2 = "1.0" quote = "1.0" From e9b5a04a4f1f13d8ecb83211132618b5de6af748 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 20 Mar 2023 20:01:56 -0400 Subject: [PATCH 253/420] Fix build --- postgres-derive/src/fromsql.rs | 12 ++++++------ postgres-derive/src/overrides.rs | 21 ++++++++++++--------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/postgres-derive/src/fromsql.rs b/postgres-derive/src/fromsql.rs index f458c6e3d..bb87ded5f 100644 --- a/postgres-derive/src/fromsql.rs +++ b/postgres-derive/src/fromsql.rs @@ -3,10 +3,10 @@ use quote::{format_ident, quote}; use std::iter; use syn::{ punctuated::Punctuated, token, AngleBracketedGenericArguments, Data, DataStruct, DeriveInput, - Error, Fields, GenericArgument, GenericParam, Generics, Ident, Lifetime, LifetimeDef, - PathArguments, PathSegment, + Error, Fields, GenericArgument, GenericParam, Generics, Ident, Lifetime, PathArguments, + PathSegment, }; -use syn::{TraitBound, TraitBoundModifier, TypeParamBound}; +use syn::{LifetimeParam, TraitBound, TraitBoundModifier, TypeParamBound}; use crate::accepts; use crate::composites::Field; @@ -96,9 +96,9 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result { let (impl_generics, _, _) = generics.split_for_impl(); let (_, ty_generics, where_clause) = input.generics.split_for_impl(); let out = quote! { - impl#impl_generics postgres_types::FromSql<#lifetime> for #ident#ty_generics #where_clause { + impl #impl_generics postgres_types::FromSql<#lifetime> for #ident #ty_generics #where_clause { fn from_sql(_type: &postgres_types::Type, buf: &#lifetime [u8]) - -> std::result::Result<#ident#ty_generics, + -> std::result::Result<#ident #ty_generics, std::boxed::Box> { @@ -217,7 +217,7 @@ fn build_generics(source: &Generics) -> (Generics, Lifetime) { let mut out = append_generic_bound(source.to_owned(), &new_fromsql_bound(&lifetime)); out.params.insert( 0, - GenericParam::Lifetime(LifetimeDef::new(lifetime.to_owned())), + GenericParam::Lifetime(LifetimeParam::new(lifetime.to_owned())), ); (out, lifetime) diff --git a/postgres-derive/src/overrides.rs b/postgres-derive/src/overrides.rs index c00d5a94b..ddb37688b 100644 --- a/postgres-derive/src/overrides.rs +++ b/postgres-derive/src/overrides.rs @@ -1,4 +1,5 @@ -use syn::{Attribute, Error, Lit, Meta, NestedMeta}; +use syn::punctuated::Punctuated; +use syn::{Attribute, Error, Expr, ExprLit, Lit, Meta, Token}; pub struct Overrides { pub name: Option, @@ -13,26 +14,28 @@ impl Overrides { }; for attr in attrs { - let attr = attr.parse_meta()?; - if !attr.path().is_ident("postgres") { continue; } - let list = match attr { + let list = match &attr.meta { Meta::List(ref list) => list, bad => return Err(Error::new_spanned(bad, "expected a #[postgres(...)]")), }; - for item in &list.nested { + let nested = list.parse_args_with(Punctuated::::parse_terminated)?; + + for item in nested { match item { - NestedMeta::Meta(Meta::NameValue(meta)) => { + Meta::NameValue(meta) => { if !meta.path.is_ident("name") { return Err(Error::new_spanned(&meta.path, "unknown override")); } - let value = match &meta.lit { - Lit::Str(s) => s.value(), + let value = match &meta.value { + Expr::Lit(ExprLit { + lit: Lit::Str(lit), .. + }) => lit.value(), bad => { return Err(Error::new_spanned(bad, "expected a string literal")) } @@ -40,7 +43,7 @@ impl Overrides { overrides.name = Some(value); } - NestedMeta::Meta(Meta::Path(ref path)) => { + Meta::Path(path) => { if !path.is_ident("transparent") { return Err(Error::new_spanned(path, "unknown override")); } From b4c05f4f81152f430bb196a5b1956e1e36a6fcff Mon Sep 17 00:00:00 2001 From: Paul Hemberger Date: Fri, 24 Mar 2023 11:46:20 -0400 Subject: [PATCH 254/420] wire through knob for TCP user timeout --- tokio-postgres/Cargo.toml | 2 +- tokio-postgres/src/cancel_query.rs | 1 + tokio-postgres/src/client.rs | 1 + tokio-postgres/src/config.rs | 14 ++++++++++++++ tokio-postgres/src/connect.rs | 2 ++ tokio-postgres/src/connect_socket.rs | 12 +++++++++++- 6 files changed, 30 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 68737f738..807698f88 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -55,7 +55,7 @@ pin-project-lite = "0.2" phf = "0.11" postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" } postgres-types = { version = "0.2.4", path = "../postgres-types" } -socket2 = "0.4" +socket2 = { version = "0.4", features = ["all"] } tokio = { version = "1.0", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } diff --git a/tokio-postgres/src/cancel_query.rs b/tokio-postgres/src/cancel_query.rs index b02729f85..022278804 100644 --- a/tokio-postgres/src/cancel_query.rs +++ b/tokio-postgres/src/cancel_query.rs @@ -38,6 +38,7 @@ where &config.host, config.port, config.connect_timeout, + config.user_timeout, config.keepalive.as_ref(), ) .await?; diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 5d0d2c536..9760ee55b 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -156,6 +156,7 @@ pub(crate) struct SocketConfig { pub host: Host, pub port: u16, pub connect_timeout: Option, + pub user_timeout: Option, pub keepalive: Option, } diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 5b364ec06..5930fbd9e 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -160,6 +160,7 @@ pub struct Config { pub(crate) host: Vec, pub(crate) port: Vec, pub(crate) connect_timeout: Option, + pub(crate) user_timeout: Option, pub(crate) keepalives: bool, pub(crate) keepalive_config: KeepaliveConfig, pub(crate) target_session_attrs: TargetSessionAttrs, @@ -190,6 +191,7 @@ impl Config { host: vec![], port: vec![], connect_timeout: None, + user_timeout: None, keepalives: true, keepalive_config, target_session_attrs: TargetSessionAttrs::Any, @@ -340,6 +342,18 @@ impl Config { self.connect_timeout.as_ref() } + /// Sets the TCP user timeout. + pub fn user_timeout(&mut self, user_timeout: Duration) -> &mut Config { + self.user_timeout = Some(user_timeout); + self + } + + /// Gets the TCP user timeout, if one has been set with the + /// `user_timeout` method. + pub fn get_user_timeout(&self) -> Option<&Duration> { + self.user_timeout.as_ref() + } + /// Controls the use of TCP keepalive. /// /// This is ignored for Unix domain socket connections. Defaults to `true`. diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 97a00c812..0006be154 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -65,6 +65,7 @@ where host, port, config.connect_timeout, + config.user_timeout, if config.keepalives { Some(&config.keepalive_config) } else { @@ -118,6 +119,7 @@ where host: host.clone(), port, connect_timeout: config.connect_timeout, + user_timeout: config.user_timeout, keepalive: if config.keepalives { Some(config.keepalive_config.clone()) } else { diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 19d01d87a..3380ccae9 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -14,6 +14,7 @@ pub(crate) async fn connect_socket( host: &Host, port: u16, connect_timeout: Option, + user_timeout: Option, keepalive_config: Option<&KeepaliveConfig>, ) -> Result { match host { @@ -35,8 +36,17 @@ pub(crate) async fn connect_socket( }; stream.set_nodelay(true).map_err(Error::connect)?; + + let sock_ref = SockRef::from(&stream); + #[cfg(target_os = "linux")] + { + sock_ref + .set_tcp_user_timeout(user_timeout) + .map_err(Error::timeout)?; + } + if let Some(keepalive_config) = keepalive_config { - SockRef::from(&stream) + sock_ref .set_tcp_keepalive(&TcpKeepalive::from(keepalive_config)) .map_err(Error::connect)?; } From ee5a139028f9f470f4adae61d80e0404fe310ab2 Mon Sep 17 00:00:00 2001 From: Paul Hemberger Date: Fri, 24 Mar 2023 13:11:18 -0400 Subject: [PATCH 255/420] add in to param parsing; update doc --- tokio-postgres/src/cancel_query.rs | 2 +- tokio-postgres/src/client.rs | 2 +- tokio-postgres/src/config.rs | 28 ++++++++++++++++++++++------ tokio-postgres/src/connect.rs | 4 ++-- tokio-postgres/src/connect_socket.rs | 4 ++-- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/tokio-postgres/src/cancel_query.rs b/tokio-postgres/src/cancel_query.rs index 022278804..d869b5824 100644 --- a/tokio-postgres/src/cancel_query.rs +++ b/tokio-postgres/src/cancel_query.rs @@ -38,7 +38,7 @@ where &config.host, config.port, config.connect_timeout, - config.user_timeout, + config.tcp_user_timeout, config.keepalive.as_ref(), ) .await?; diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 9760ee55b..8b7df4e87 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -156,7 +156,7 @@ pub(crate) struct SocketConfig { pub host: Host, pub port: u16, pub connect_timeout: Option, - pub user_timeout: Option, + pub tcp_user_timeout: Option, pub keepalive: Option, } diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 5930fbd9e..fd848153f 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -96,6 +96,9 @@ pub enum Host { /// omitted or the empty string. /// * `connect_timeout` - The time limit in seconds applied to each socket-level connection attempt. Note that hostnames /// can resolve to multiple IP addresses, and this limit is applied to each address. Defaults to no timeout. +/// * `tcp_user_timeout` - The time limit that transmitted data may remain unacknowledged before a connection is forcibly closed. +/// This is ignored for Unix domain socket connections. It is only supported on systems where TCP_USER_TIMEOUT is available +/// and will default to the system default; on other systems, it has no effect. /// * `keepalives` - Controls the use of TCP keepalive. A value of 0 disables keepalive and nonzero integers enable it. /// This option is ignored when connecting with Unix sockets. Defaults to on. /// * `keepalives_idle` - The number of seconds of inactivity after which a keepalive message is sent to the server. @@ -160,7 +163,7 @@ pub struct Config { pub(crate) host: Vec, pub(crate) port: Vec, pub(crate) connect_timeout: Option, - pub(crate) user_timeout: Option, + pub(crate) tcp_user_timeout: Option, pub(crate) keepalives: bool, pub(crate) keepalive_config: KeepaliveConfig, pub(crate) target_session_attrs: TargetSessionAttrs, @@ -191,7 +194,7 @@ impl Config { host: vec![], port: vec![], connect_timeout: None, - user_timeout: None, + tcp_user_timeout: None, keepalives: true, keepalive_config, target_session_attrs: TargetSessionAttrs::Any, @@ -343,15 +346,19 @@ impl Config { } /// Sets the TCP user timeout. - pub fn user_timeout(&mut self, user_timeout: Duration) -> &mut Config { - self.user_timeout = Some(user_timeout); + /// + /// This is ignored for Unix domain socket connections. It is only supported on systems where + /// TCP_USER_TIMEOUT is available and will default to the system default; on other systems, + /// it has no effect. + pub fn tcp_user_timeout(&mut self, tcp_user_timeout: Duration) -> &mut Config { + self.tcp_user_timeout = Some(tcp_user_timeout); self } /// Gets the TCP user timeout, if one has been set with the /// `user_timeout` method. - pub fn get_user_timeout(&self) -> Option<&Duration> { - self.user_timeout.as_ref() + pub fn get_tcp_user_timeout(&self) -> Option<&Duration> { + self.tcp_user_timeout.as_ref() } /// Controls the use of TCP keepalive. @@ -488,6 +495,14 @@ impl Config { self.connect_timeout(Duration::from_secs(timeout as u64)); } } + "tcp_user_timeout" => { + let timeout = value + .parse::() + .map_err(|_| Error::config_parse(Box::new(InvalidValue("tcp_user_timeout"))))?; + if timeout > 0 { + self.tcp_user_timeout(Duration::from_secs(timeout as u64)); + } + } "keepalives" => { let keepalives = value .parse::() @@ -609,6 +624,7 @@ impl fmt::Debug for Config { .field("host", &self.host) .field("port", &self.port) .field("connect_timeout", &self.connect_timeout) + .field("tcp_user_timeout", &self.tcp_user_timeout) .field("keepalives", &self.keepalives) .field("keepalives_idle", &self.keepalive_config.idle) .field("keepalives_interval", &self.keepalive_config.interval) diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 0006be154..ed7ecac66 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -65,7 +65,7 @@ where host, port, config.connect_timeout, - config.user_timeout, + config.tcp_user_timeout, if config.keepalives { Some(&config.keepalive_config) } else { @@ -119,7 +119,7 @@ where host: host.clone(), port, connect_timeout: config.connect_timeout, - user_timeout: config.user_timeout, + tcp_user_timeout: config.tcp_user_timeout, keepalive: if config.keepalives { Some(config.keepalive_config.clone()) } else { diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 3380ccae9..7937df280 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -14,7 +14,7 @@ pub(crate) async fn connect_socket( host: &Host, port: u16, connect_timeout: Option, - user_timeout: Option, + tcp_user_timeout: Option, keepalive_config: Option<&KeepaliveConfig>, ) -> Result { match host { @@ -41,7 +41,7 @@ pub(crate) async fn connect_socket( #[cfg(target_os = "linux")] { sock_ref - .set_tcp_user_timeout(user_timeout) + .set_tcp_user_timeout(tcp_user_timeout) .map_err(Error::timeout)?; } From 071dfa3f3b217a32b1e2ab3db9e6ab5132f2fcd1 Mon Sep 17 00:00:00 2001 From: jaydenelliott Date: Sun, 26 Mar 2023 20:33:29 +1100 Subject: [PATCH 256/420] added a rename_all container attribute for enums and structs --- postgres-derive-test/src/composites.rs | 43 +++++++ postgres-derive-test/src/enums.rs | 29 +++++ postgres-derive/src/case.rs | 158 +++++++++++++++++++++++++ postgres-derive/src/composites.rs | 26 ++-- postgres-derive/src/enums.rs | 13 +- postgres-derive/src/fromsql.rs | 9 +- postgres-derive/src/lib.rs | 1 + postgres-derive/src/overrides.rs | 32 ++++- postgres-derive/src/tosql.rs | 9 +- 9 files changed, 299 insertions(+), 21 deletions(-) create mode 100644 postgres-derive/src/case.rs diff --git a/postgres-derive-test/src/composites.rs b/postgres-derive-test/src/composites.rs index a1b76345f..50a22790d 100644 --- a/postgres-derive-test/src/composites.rs +++ b/postgres-derive-test/src/composites.rs @@ -89,6 +89,49 @@ fn name_overrides() { ); } +#[test] +fn rename_all_overrides() { + #[derive(FromSql, ToSql, Debug, PartialEq)] + #[postgres(name = "inventory_item", rename_all = "SCREAMING_SNAKE_CASE")] + struct InventoryItem { + name: String, + supplier_id: i32, + #[postgres(name = "Price")] + price: Option, + } + + let mut conn = Client::connect("user=postgres host=localhost port=5433", NoTls).unwrap(); + conn.batch_execute( + "CREATE TYPE pg_temp.inventory_item AS ( + \"NAME\" TEXT, + \"SUPPLIER_ID\" INT, + \"Price\" DOUBLE PRECISION + );", + ) + .unwrap(); + + let item = InventoryItem { + name: "foobar".to_owned(), + supplier_id: 100, + price: Some(15.50), + }; + + let item_null = InventoryItem { + name: "foobar".to_owned(), + supplier_id: 100, + price: None, + }; + + test_type( + &mut conn, + "inventory_item", + &[ + (item, "ROW('foobar', 100, 15.50)"), + (item_null, "ROW('foobar', 100, NULL)"), + ], + ); +} + #[test] fn wrong_name() { #[derive(FromSql, ToSql, Debug, PartialEq)] diff --git a/postgres-derive-test/src/enums.rs b/postgres-derive-test/src/enums.rs index a7039ca05..e44f37616 100644 --- a/postgres-derive-test/src/enums.rs +++ b/postgres-derive-test/src/enums.rs @@ -53,6 +53,35 @@ fn name_overrides() { ); } +#[test] +fn rename_all_overrides() { + #[derive(Debug, ToSql, FromSql, PartialEq)] + #[postgres(name = "mood", rename_all = "snake_case")] + enum Mood { + Sad, + #[postgres(name = "okay")] + Ok, + Happy, + } + + let mut conn = Client::connect("user=postgres host=localhost port=5433", NoTls).unwrap(); + conn.execute( + "CREATE TYPE pg_temp.mood AS ENUM ('sad', 'okay', 'happy')", + &[], + ) + .unwrap(); + + test_type( + &mut conn, + "mood", + &[ + (Mood::Sad, "'sad'"), + (Mood::Ok, "'okay'"), + (Mood::Happy, "'happy'"), + ], + ); +} + #[test] fn wrong_name() { #[derive(Debug, ToSql, FromSql, PartialEq)] diff --git a/postgres-derive/src/case.rs b/postgres-derive/src/case.rs new file mode 100644 index 000000000..b128990c5 --- /dev/null +++ b/postgres-derive/src/case.rs @@ -0,0 +1,158 @@ +#[allow(deprecated, unused_imports)] +use std::ascii::AsciiExt; + +use self::RenameRule::*; + +/// The different possible ways to change case of fields in a struct, or variants in an enum. +#[allow(clippy::enum_variant_names)] +#[derive(Copy, Clone, PartialEq)] +pub enum RenameRule { + /// Rename direct children to "lowercase" style. + LowerCase, + /// Rename direct children to "UPPERCASE" style. + UpperCase, + /// Rename direct children to "PascalCase" style, as typically used for + /// enum variants. + PascalCase, + /// Rename direct children to "camelCase" style. + CamelCase, + /// Rename direct children to "snake_case" style, as commonly used for + /// fields. + SnakeCase, + /// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly + /// used for constants. + ScreamingSnakeCase, + /// Rename direct children to "kebab-case" style. + KebabCase, + /// Rename direct children to "SCREAMING-KEBAB-CASE" style. + ScreamingKebabCase, +} + +pub static RENAME_RULES: &[(&str, RenameRule)] = &[ + ("lowercase", LowerCase), + ("UPPERCASE", UpperCase), + ("PascalCase", PascalCase), + ("camelCase", CamelCase), + ("snake_case", SnakeCase), + ("SCREAMING_SNAKE_CASE", ScreamingSnakeCase), + ("kebab-case", KebabCase), + ("SCREAMING-KEBAB-CASE", ScreamingKebabCase), +]; + +impl RenameRule { + /// Apply a renaming rule to an enum variant, returning the version expected in the source. + pub fn apply_to_variant(&self, variant: &str) -> String { + match *self { + PascalCase => variant.to_owned(), + LowerCase => variant.to_ascii_lowercase(), + UpperCase => variant.to_ascii_uppercase(), + CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..], + SnakeCase => { + let mut snake = String::new(); + for (i, ch) in variant.char_indices() { + if i > 0 && ch.is_uppercase() { + snake.push('_'); + } + snake.push(ch.to_ascii_lowercase()); + } + snake + } + ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(), + KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"), + ScreamingKebabCase => ScreamingSnakeCase + .apply_to_variant(variant) + .replace('_', "-"), + } + } + + /// Apply a renaming rule to a struct field, returning the version expected in the source. + pub fn apply_to_field(&self, field: &str) -> String { + match *self { + LowerCase | SnakeCase => field.to_owned(), + UpperCase => field.to_ascii_uppercase(), + PascalCase => { + let mut pascal = String::new(); + let mut capitalize = true; + for ch in field.chars() { + if ch == '_' { + capitalize = true; + } else if capitalize { + pascal.push(ch.to_ascii_uppercase()); + capitalize = false; + } else { + pascal.push(ch); + } + } + pascal + } + CamelCase => { + let pascal = PascalCase.apply_to_field(field); + pascal[..1].to_ascii_lowercase() + &pascal[1..] + } + ScreamingSnakeCase => field.to_ascii_uppercase(), + KebabCase => field.replace('_', "-"), + ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"), + } + } +} + +#[test] +fn rename_variants() { + for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[ + ( + "Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME", + ), + ( + "VeryTasty", + "verytasty", + "VERYTASTY", + "veryTasty", + "very_tasty", + "VERY_TASTY", + "very-tasty", + "VERY-TASTY", + ), + ("A", "a", "A", "a", "a", "A", "a", "A"), + ("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"), + ] { + assert_eq!(LowerCase.apply_to_variant(original), lower); + assert_eq!(UpperCase.apply_to_variant(original), upper); + assert_eq!(PascalCase.apply_to_variant(original), original); + assert_eq!(CamelCase.apply_to_variant(original), camel); + assert_eq!(SnakeCase.apply_to_variant(original), snake); + assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming); + assert_eq!(KebabCase.apply_to_variant(original), kebab); + assert_eq!( + ScreamingKebabCase.apply_to_variant(original), + screaming_kebab + ); + } +} + +#[test] +fn rename_fields() { + for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[ + ( + "outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME", + ), + ( + "very_tasty", + "VERY_TASTY", + "VeryTasty", + "veryTasty", + "VERY_TASTY", + "very-tasty", + "VERY-TASTY", + ), + ("a", "A", "A", "a", "A", "a", "A"), + ("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"), + ] { + assert_eq!(UpperCase.apply_to_field(original), upper); + assert_eq!(PascalCase.apply_to_field(original), pascal); + assert_eq!(CamelCase.apply_to_field(original), camel); + assert_eq!(SnakeCase.apply_to_field(original), original); + assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming); + assert_eq!(KebabCase.apply_to_field(original), kebab); + assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab); + } +} diff --git a/postgres-derive/src/composites.rs b/postgres-derive/src/composites.rs index 15bfabc13..dcff2c581 100644 --- a/postgres-derive/src/composites.rs +++ b/postgres-derive/src/composites.rs @@ -4,7 +4,7 @@ use syn::{ TypeParamBound, }; -use crate::overrides::Overrides; +use crate::{case::RenameRule, overrides::Overrides}; pub struct Field { pub name: String, @@ -13,18 +13,26 @@ pub struct Field { } impl Field { - pub fn parse(raw: &syn::Field) -> Result { + pub fn parse(raw: &syn::Field, rename_all: Option) -> Result { let overrides = Overrides::extract(&raw.attrs)?; - let ident = raw.ident.as_ref().unwrap().clone(); - Ok(Field { - name: overrides.name.unwrap_or_else(|| { + + // field level name override takes precendence over container level rename_all override + let name = match overrides.name { + Some(n) => n, + None => { let name = ident.to_string(); - match name.strip_prefix("r#") { - Some(name) => name.to_string(), - None => name, + let stripped = name.strip_prefix("r#").map(String::from).unwrap_or(name); + + match rename_all { + Some(rule) => rule.apply_to_field(&stripped), + None => stripped, } - }), + } + }; + + Ok(Field { + name, ident, type_: raw.ty.clone(), }) diff --git a/postgres-derive/src/enums.rs b/postgres-derive/src/enums.rs index 3c6bc7113..d99eca1c4 100644 --- a/postgres-derive/src/enums.rs +++ b/postgres-derive/src/enums.rs @@ -1,6 +1,6 @@ use syn::{Error, Fields, Ident}; -use crate::overrides::Overrides; +use crate::{case::RenameRule, overrides::Overrides}; pub struct Variant { pub ident: Ident, @@ -8,7 +8,7 @@ pub struct Variant { } impl Variant { - pub fn parse(raw: &syn::Variant) -> Result { + pub fn parse(raw: &syn::Variant, rename_all: Option) -> Result { match raw.fields { Fields::Unit => {} _ => { @@ -18,11 +18,16 @@ impl Variant { )) } } - let overrides = Overrides::extract(&raw.attrs)?; + + // variant level name override takes precendence over container level rename_all override + let name = overrides.name.unwrap_or_else(|| match rename_all { + Some(rule) => rule.apply_to_variant(&raw.ident.to_string()), + None => raw.ident.to_string(), + }); Ok(Variant { ident: raw.ident.clone(), - name: overrides.name.unwrap_or_else(|| raw.ident.to_string()), + name, }) } } diff --git a/postgres-derive/src/fromsql.rs b/postgres-derive/src/fromsql.rs index bb87ded5f..3736e01e9 100644 --- a/postgres-derive/src/fromsql.rs +++ b/postgres-derive/src/fromsql.rs @@ -24,7 +24,10 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result { )); } - let name = overrides.name.unwrap_or_else(|| input.ident.to_string()); + let name = overrides + .name + .clone() + .unwrap_or_else(|| input.ident.to_string()); let (accepts_body, to_sql_body) = if overrides.transparent { match input.data { @@ -51,7 +54,7 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result { let variants = data .variants .iter() - .map(Variant::parse) + .map(|variant| Variant::parse(variant, overrides.rename_all)) .collect::, _>>()?; ( accepts::enum_body(&name, &variants), @@ -75,7 +78,7 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result { let fields = fields .named .iter() - .map(Field::parse) + .map(|field| Field::parse(field, overrides.rename_all)) .collect::, _>>()?; ( accepts::composite_body(&name, "FromSql", &fields), diff --git a/postgres-derive/src/lib.rs b/postgres-derive/src/lib.rs index 98e6add24..b849096c9 100644 --- a/postgres-derive/src/lib.rs +++ b/postgres-derive/src/lib.rs @@ -7,6 +7,7 @@ use proc_macro::TokenStream; use syn::parse_macro_input; mod accepts; +mod case; mod composites; mod enums; mod fromsql; diff --git a/postgres-derive/src/overrides.rs b/postgres-derive/src/overrides.rs index ddb37688b..3918446a2 100644 --- a/postgres-derive/src/overrides.rs +++ b/postgres-derive/src/overrides.rs @@ -1,8 +1,11 @@ use syn::punctuated::Punctuated; use syn::{Attribute, Error, Expr, ExprLit, Lit, Meta, Token}; +use crate::case::{RenameRule, RENAME_RULES}; + pub struct Overrides { pub name: Option, + pub rename_all: Option, pub transparent: bool, } @@ -10,6 +13,7 @@ impl Overrides { pub fn extract(attrs: &[Attribute]) -> Result { let mut overrides = Overrides { name: None, + rename_all: None, transparent: false, }; @@ -28,7 +32,9 @@ impl Overrides { for item in nested { match item { Meta::NameValue(meta) => { - if !meta.path.is_ident("name") { + let name_override = meta.path.is_ident("name"); + let rename_all_override = meta.path.is_ident("rename_all"); + if !name_override && !rename_all_override { return Err(Error::new_spanned(&meta.path, "unknown override")); } @@ -41,7 +47,29 @@ impl Overrides { } }; - overrides.name = Some(value); + if name_override { + overrides.name = Some(value); + } else if rename_all_override { + let rename_rule = RENAME_RULES + .iter() + .find(|rule| rule.0 == value) + .map(|val| val.1) + .ok_or_else(|| { + Error::new_spanned( + &meta.value, + format!( + "invalid rename_all rule, expected one of: {}", + RENAME_RULES + .iter() + .map(|rule| format!("\"{}\"", rule.0)) + .collect::>() + .join(", ") + ), + ) + })?; + + overrides.rename_all = Some(rename_rule); + } } Meta::Path(path) => { if !path.is_ident("transparent") { diff --git a/postgres-derive/src/tosql.rs b/postgres-derive/src/tosql.rs index e51acc7fd..1e91df4f6 100644 --- a/postgres-derive/src/tosql.rs +++ b/postgres-derive/src/tosql.rs @@ -22,7 +22,10 @@ pub fn expand_derive_tosql(input: DeriveInput) -> Result { )); } - let name = overrides.name.unwrap_or_else(|| input.ident.to_string()); + let name = overrides + .name + .clone() + .unwrap_or_else(|| input.ident.to_string()); let (accepts_body, to_sql_body) = if overrides.transparent { match input.data { @@ -47,7 +50,7 @@ pub fn expand_derive_tosql(input: DeriveInput) -> Result { let variants = data .variants .iter() - .map(Variant::parse) + .map(|variant| Variant::parse(variant, overrides.rename_all)) .collect::, _>>()?; ( accepts::enum_body(&name, &variants), @@ -69,7 +72,7 @@ pub fn expand_derive_tosql(input: DeriveInput) -> Result { let fields = fields .named .iter() - .map(Field::parse) + .map(|field| Field::parse(field, overrides.rename_all)) .collect::, _>>()?; ( accepts::composite_body(&name, "ToSql", &fields), From bc8ad8aee69f14e367de2f42c8d3a61c1d9c144b Mon Sep 17 00:00:00 2001 From: jaydenelliott Date: Mon, 27 Mar 2023 18:22:53 +1100 Subject: [PATCH 257/420] Distinguish between field and container attributes when parsing --- postgres-derive/src/composites.rs | 2 +- postgres-derive/src/enums.rs | 2 +- postgres-derive/src/fromsql.rs | 2 +- postgres-derive/src/overrides.rs | 8 +++++++- postgres-derive/src/tosql.rs | 2 +- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/postgres-derive/src/composites.rs b/postgres-derive/src/composites.rs index dcff2c581..b6aad8ab3 100644 --- a/postgres-derive/src/composites.rs +++ b/postgres-derive/src/composites.rs @@ -14,7 +14,7 @@ pub struct Field { impl Field { pub fn parse(raw: &syn::Field, rename_all: Option) -> Result { - let overrides = Overrides::extract(&raw.attrs)?; + let overrides = Overrides::extract(&raw.attrs, false)?; let ident = raw.ident.as_ref().unwrap().clone(); // field level name override takes precendence over container level rename_all override diff --git a/postgres-derive/src/enums.rs b/postgres-derive/src/enums.rs index d99eca1c4..3e4b5045f 100644 --- a/postgres-derive/src/enums.rs +++ b/postgres-derive/src/enums.rs @@ -18,7 +18,7 @@ impl Variant { )) } } - let overrides = Overrides::extract(&raw.attrs)?; + let overrides = Overrides::extract(&raw.attrs, false)?; // variant level name override takes precendence over container level rename_all override let name = overrides.name.unwrap_or_else(|| match rename_all { diff --git a/postgres-derive/src/fromsql.rs b/postgres-derive/src/fromsql.rs index 3736e01e9..4deb23ed2 100644 --- a/postgres-derive/src/fromsql.rs +++ b/postgres-derive/src/fromsql.rs @@ -15,7 +15,7 @@ use crate::enums::Variant; use crate::overrides::Overrides; pub fn expand_derive_fromsql(input: DeriveInput) -> Result { - let overrides = Overrides::extract(&input.attrs)?; + let overrides = Overrides::extract(&input.attrs, true)?; if overrides.name.is_some() && overrides.transparent { return Err(Error::new_spanned( diff --git a/postgres-derive/src/overrides.rs b/postgres-derive/src/overrides.rs index 3918446a2..7f28375bc 100644 --- a/postgres-derive/src/overrides.rs +++ b/postgres-derive/src/overrides.rs @@ -10,7 +10,7 @@ pub struct Overrides { } impl Overrides { - pub fn extract(attrs: &[Attribute]) -> Result { + pub fn extract(attrs: &[Attribute], container_attr: bool) -> Result { let mut overrides = Overrides { name: None, rename_all: None, @@ -34,6 +34,12 @@ impl Overrides { Meta::NameValue(meta) => { let name_override = meta.path.is_ident("name"); let rename_all_override = meta.path.is_ident("rename_all"); + if !container_attr && rename_all_override { + return Err(Error::new_spanned( + &meta.path, + "rename_all is a container attribute", + )); + } if !name_override && !rename_all_override { return Err(Error::new_spanned(&meta.path, "unknown override")); } diff --git a/postgres-derive/src/tosql.rs b/postgres-derive/src/tosql.rs index 1e91df4f6..dbeeb16c3 100644 --- a/postgres-derive/src/tosql.rs +++ b/postgres-derive/src/tosql.rs @@ -13,7 +13,7 @@ use crate::enums::Variant; use crate::overrides::Overrides; pub fn expand_derive_tosql(input: DeriveInput) -> Result { - let overrides = Overrides::extract(&input.attrs)?; + let overrides = Overrides::extract(&input.attrs, true)?; if overrides.name.is_some() && overrides.transparent { return Err(Error::new_spanned( From d509b3bc52df9cf0d7f1f2ac5ac64b0bfc643160 Mon Sep 17 00:00:00 2001 From: jaydenelliott Date: Mon, 27 Mar 2023 18:45:05 +1100 Subject: [PATCH 258/420] Replaced case conversion with heck --- postgres-derive/Cargo.toml | 1 + postgres-derive/src/case.rs | 138 ++++++++++--------------------- postgres-derive/src/enums.rs | 2 +- postgres-derive/src/overrides.rs | 30 +++---- 4 files changed, 60 insertions(+), 111 deletions(-) diff --git a/postgres-derive/Cargo.toml b/postgres-derive/Cargo.toml index 8470bc8a9..cfc8829f4 100644 --- a/postgres-derive/Cargo.toml +++ b/postgres-derive/Cargo.toml @@ -15,3 +15,4 @@ test = false syn = "2.0" proc-macro2 = "1.0" quote = "1.0" +heck = "0.4" \ No newline at end of file diff --git a/postgres-derive/src/case.rs b/postgres-derive/src/case.rs index b128990c5..20ecc8eed 100644 --- a/postgres-derive/src/case.rs +++ b/postgres-derive/src/case.rs @@ -1,6 +1,11 @@ #[allow(deprecated, unused_imports)] use std::ascii::AsciiExt; +use heck::{ + ToKebabCase, ToLowerCamelCase, ToShoutyKebabCase, ToShoutySnakeCase, ToSnakeCase, ToTrainCase, + ToUpperCamelCase, +}; + use self::RenameRule::*; /// The different possible ways to change case of fields in a struct, or variants in an enum. @@ -26,78 +31,56 @@ pub enum RenameRule { KebabCase, /// Rename direct children to "SCREAMING-KEBAB-CASE" style. ScreamingKebabCase, + + /// Rename direct children to "Train-Case" style. + TrainCase, } -pub static RENAME_RULES: &[(&str, RenameRule)] = &[ - ("lowercase", LowerCase), - ("UPPERCASE", UpperCase), - ("PascalCase", PascalCase), - ("camelCase", CamelCase), - ("snake_case", SnakeCase), - ("SCREAMING_SNAKE_CASE", ScreamingSnakeCase), - ("kebab-case", KebabCase), - ("SCREAMING-KEBAB-CASE", ScreamingKebabCase), +pub const RENAME_RULES: &[&str] = &[ + "lowercase", + "UPPERCASE", + "PascalCase", + "camelCase", + "snake_case", + "SCREAMING_SNAKE_CASE", + "kebab-case", + "SCREAMING-KEBAB-CASE", + "Train-Case", ]; impl RenameRule { - /// Apply a renaming rule to an enum variant, returning the version expected in the source. - pub fn apply_to_variant(&self, variant: &str) -> String { - match *self { - PascalCase => variant.to_owned(), - LowerCase => variant.to_ascii_lowercase(), - UpperCase => variant.to_ascii_uppercase(), - CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..], - SnakeCase => { - let mut snake = String::new(); - for (i, ch) in variant.char_indices() { - if i > 0 && ch.is_uppercase() { - snake.push('_'); - } - snake.push(ch.to_ascii_lowercase()); - } - snake - } - ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(), - KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"), - ScreamingKebabCase => ScreamingSnakeCase - .apply_to_variant(variant) - .replace('_', "-"), + pub fn from_str(rule: &str) -> Option { + match rule { + "lowercase" => Some(LowerCase), + "UPPERCASE" => Some(UpperCase), + "PascalCase" => Some(PascalCase), + "camelCase" => Some(CamelCase), + "snake_case" => Some(SnakeCase), + "SCREAMING_SNAKE_CASE" => Some(ScreamingSnakeCase), + "kebab-case" => Some(KebabCase), + "SCREAMING-KEBAB-CASE" => Some(ScreamingKebabCase), + "Train-Case" => Some(TrainCase), + _ => None, } } - - /// Apply a renaming rule to a struct field, returning the version expected in the source. - pub fn apply_to_field(&self, field: &str) -> String { + /// Apply a renaming rule to an enum or struct field, returning the version expected in the source. + pub fn apply_to_field(&self, variant: &str) -> String { match *self { - LowerCase | SnakeCase => field.to_owned(), - UpperCase => field.to_ascii_uppercase(), - PascalCase => { - let mut pascal = String::new(); - let mut capitalize = true; - for ch in field.chars() { - if ch == '_' { - capitalize = true; - } else if capitalize { - pascal.push(ch.to_ascii_uppercase()); - capitalize = false; - } else { - pascal.push(ch); - } - } - pascal - } - CamelCase => { - let pascal = PascalCase.apply_to_field(field); - pascal[..1].to_ascii_lowercase() + &pascal[1..] - } - ScreamingSnakeCase => field.to_ascii_uppercase(), - KebabCase => field.replace('_', "-"), - ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"), + LowerCase => variant.to_lowercase(), + UpperCase => variant.to_uppercase(), + PascalCase => variant.to_upper_camel_case(), + CamelCase => variant.to_lower_camel_case(), + SnakeCase => variant.to_snake_case(), + ScreamingSnakeCase => variant.to_shouty_snake_case(), + KebabCase => variant.to_kebab_case(), + ScreamingKebabCase => variant.to_shouty_kebab_case(), + TrainCase => variant.to_train_case(), } } } #[test] -fn rename_variants() { +fn rename_field() { for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[ ( "Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME", @@ -115,42 +98,11 @@ fn rename_variants() { ("A", "a", "A", "a", "a", "A", "a", "A"), ("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"), ] { - assert_eq!(LowerCase.apply_to_variant(original), lower); - assert_eq!(UpperCase.apply_to_variant(original), upper); - assert_eq!(PascalCase.apply_to_variant(original), original); - assert_eq!(CamelCase.apply_to_variant(original), camel); - assert_eq!(SnakeCase.apply_to_variant(original), snake); - assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming); - assert_eq!(KebabCase.apply_to_variant(original), kebab); - assert_eq!( - ScreamingKebabCase.apply_to_variant(original), - screaming_kebab - ); - } -} - -#[test] -fn rename_fields() { - for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[ - ( - "outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME", - ), - ( - "very_tasty", - "VERY_TASTY", - "VeryTasty", - "veryTasty", - "VERY_TASTY", - "very-tasty", - "VERY-TASTY", - ), - ("a", "A", "A", "a", "A", "a", "A"), - ("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"), - ] { + assert_eq!(LowerCase.apply_to_field(original), lower); assert_eq!(UpperCase.apply_to_field(original), upper); - assert_eq!(PascalCase.apply_to_field(original), pascal); + assert_eq!(PascalCase.apply_to_field(original), original); assert_eq!(CamelCase.apply_to_field(original), camel); - assert_eq!(SnakeCase.apply_to_field(original), original); + assert_eq!(SnakeCase.apply_to_field(original), snake); assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming); assert_eq!(KebabCase.apply_to_field(original), kebab); assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab); diff --git a/postgres-derive/src/enums.rs b/postgres-derive/src/enums.rs index 3e4b5045f..9a6dfa926 100644 --- a/postgres-derive/src/enums.rs +++ b/postgres-derive/src/enums.rs @@ -22,7 +22,7 @@ impl Variant { // variant level name override takes precendence over container level rename_all override let name = overrides.name.unwrap_or_else(|| match rename_all { - Some(rule) => rule.apply_to_variant(&raw.ident.to_string()), + Some(rule) => rule.apply_to_field(&raw.ident.to_string()), None => raw.ident.to_string(), }); Ok(Variant { diff --git a/postgres-derive/src/overrides.rs b/postgres-derive/src/overrides.rs index 7f28375bc..99faeebb7 100644 --- a/postgres-derive/src/overrides.rs +++ b/postgres-derive/src/overrides.rs @@ -56,23 +56,19 @@ impl Overrides { if name_override { overrides.name = Some(value); } else if rename_all_override { - let rename_rule = RENAME_RULES - .iter() - .find(|rule| rule.0 == value) - .map(|val| val.1) - .ok_or_else(|| { - Error::new_spanned( - &meta.value, - format!( - "invalid rename_all rule, expected one of: {}", - RENAME_RULES - .iter() - .map(|rule| format!("\"{}\"", rule.0)) - .collect::>() - .join(", ") - ), - ) - })?; + let rename_rule = RenameRule::from_str(&value).ok_or_else(|| { + Error::new_spanned( + &meta.value, + format!( + "invalid rename_all rule, expected one of: {}", + RENAME_RULES + .iter() + .map(|rule| format!("\"{}\"", rule)) + .collect::>() + .join(", ") + ), + ) + })?; overrides.rename_all = Some(rename_rule); } From a9967c05ff40de34e1471bf28cd956e756d1f6f9 Mon Sep 17 00:00:00 2001 From: Paul Hemberger Date: Mon, 27 Mar 2023 16:47:48 -0400 Subject: [PATCH 259/420] docs: mention sys default if 0 --- tokio-postgres/src/config.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index fd848153f..a8aa7a9f5 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -98,7 +98,7 @@ pub enum Host { /// can resolve to multiple IP addresses, and this limit is applied to each address. Defaults to no timeout. /// * `tcp_user_timeout` - The time limit that transmitted data may remain unacknowledged before a connection is forcibly closed. /// This is ignored for Unix domain socket connections. It is only supported on systems where TCP_USER_TIMEOUT is available -/// and will default to the system default; on other systems, it has no effect. +/// and will default to the system default if omitted or set to 0; on other systems, it has no effect. /// * `keepalives` - Controls the use of TCP keepalive. A value of 0 disables keepalive and nonzero integers enable it. /// This option is ignored when connecting with Unix sockets. Defaults to on. /// * `keepalives_idle` - The number of seconds of inactivity after which a keepalive message is sent to the server. @@ -348,8 +348,8 @@ impl Config { /// Sets the TCP user timeout. /// /// This is ignored for Unix domain socket connections. It is only supported on systems where - /// TCP_USER_TIMEOUT is available and will default to the system default; on other systems, - /// it has no effect. + /// TCP_USER_TIMEOUT is available and will default to the system default if omitted or set to 0; + /// on other systems, it has no effect. pub fn tcp_user_timeout(&mut self, tcp_user_timeout: Duration) -> &mut Config { self.tcp_user_timeout = Some(tcp_user_timeout); self From 62a443222c8f660438251ef17cb2ca088f48e207 Mon Sep 17 00:00:00 2001 From: Paul Hemberger Date: Mon, 27 Mar 2023 16:47:58 -0400 Subject: [PATCH 260/420] use correct error type --- tokio-postgres/src/connect_socket.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 7937df280..9b3d31d72 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -42,7 +42,7 @@ pub(crate) async fn connect_socket( { sock_ref .set_tcp_user_timeout(tcp_user_timeout) - .map_err(Error::timeout)?; + .map_err(Error::connect)?; } if let Some(keepalive_config) = keepalive_config { From 58f06610cc9e0437c7779ce7dad234fa7a2241c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 21:08:40 +0000 Subject: [PATCH 261/420] Update socket2 requirement from 0.4 to 0.5 Updates the requirements on [socket2](https://github.com/rust-lang/socket2) to permit the latest version. - [Release notes](https://github.com/rust-lang/socket2/releases) - [Changelog](https://github.com/rust-lang/socket2/blob/master/CHANGELOG.md) - [Commits](https://github.com/rust-lang/socket2/compare/v0.4.0...v0.5.1) --- updated-dependencies: - dependency-name: socket2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- tokio-postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 807698f88..39e41d85c 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -55,7 +55,7 @@ pin-project-lite = "0.2" phf = "0.11" postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" } postgres-types = { version = "0.2.4", path = "../postgres-types" } -socket2 = { version = "0.4", features = ["all"] } +socket2 = { version = "0.5", features = ["all"] } tokio = { version = "1.0", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } From a205d23141bb389693bf27a7e8233b5db072a7f5 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 27 Mar 2023 18:04:52 -0400 Subject: [PATCH 262/420] Update Cargo.toml --- tokio-postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 39e41d85c..c29852dec 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -56,7 +56,7 @@ phf = "0.11" postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" } postgres-types = { version = "0.2.4", path = "../postgres-types" } socket2 = { version = "0.5", features = ["all"] } -tokio = { version = "1.0", features = ["io-util"] } +tokio = { version = "1.27", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } [dev-dependencies] From 9c0d2dddc43b6137ae5bb0a540b3442b33565fa4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 27 Mar 2023 18:14:05 -0400 Subject: [PATCH 263/420] Update ci.yml --- .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 f81bdee46..8044b2f47 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: - run: docker compose up -d - uses: sfackler/actions/rustup@master with: - version: 1.63.0 + version: 1.64.0 - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - uses: actions/cache@v3 From 5be97d9559ff7077eb77486ca2c789907f58ff9c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 27 Mar 2023 18:59:29 -0400 Subject: [PATCH 264/420] Release postgres-types v0.2.5 --- postgres-types/CHANGELOG.md | 6 ++++++ postgres-types/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index 0e2167e5f..0f42f3495 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.2.5 - 2023-03-27 + +## Added + +* Added support for multi-range types. + ## v0.2.4 - 2022-08-20 ## Added diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 70f1ed54a..35cdd6e7b 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-types" -version = "0.2.4" +version = "0.2.5" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From a46796798aff0ab30e21abe9160bf1246b354626 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 27 Mar 2023 19:02:39 -0400 Subject: [PATCH 265/420] Release postgres-protocol v0.6.5 --- postgres-protocol/CHANGELOG.md | 11 +++++++++++ postgres-protocol/Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/postgres-protocol/CHANGELOG.md b/postgres-protocol/CHANGELOG.md index d84f29ded..034fd637c 100644 --- a/postgres-protocol/CHANGELOG.md +++ b/postgres-protocol/CHANGELOG.md @@ -1,5 +1,16 @@ # Change Log +## v0.6.5 - 2023-03-27 + +### Added + +* Added `message::frontend::flush`. +* Added `DataRowBody::buffer_bytes`. + +### Changed + +* Upgraded `base64`. + ## v0.6.4 - 2022-04-03 ### Added diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index 922e92313..e32211369 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-protocol" -version = "0.6.4" +version = "0.6.5" authors = ["Steven Fackler "] edition = "2018" description = "Low level Postgres protocol APIs" From 54390eb3fe8c4766c22cbaba91ffae3885af00e3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 27 Mar 2023 19:04:38 -0400 Subject: [PATCH 266/420] Release postgres-derive v0.4.4 --- postgres-derive/CHANGELOG.md | 6 ++++++ postgres-derive/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/postgres-derive/CHANGELOG.md b/postgres-derive/CHANGELOG.md index dde466a97..22714acc2 100644 --- a/postgres-derive/CHANGELOG.md +++ b/postgres-derive/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.4.4 - 2023-03-27 + +### Changed + +* Upgraded `syn`. + ## v0.4.3 - 2022-09-07 ### Added diff --git a/postgres-derive/Cargo.toml b/postgres-derive/Cargo.toml index 8470bc8a9..535a64315 100644 --- a/postgres-derive/Cargo.toml +++ b/postgres-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-derive" -version = "0.4.3" +version = "0.4.4" authors = ["Steven Fackler "] license = "MIT/Apache-2.0" edition = "2018" From 117e387a3e44c13068dca613b36037c5de35d65c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 27 Mar 2023 19:14:49 -0400 Subject: [PATCH 267/420] Release tokio-postgres v0.7.8 --- tokio-postgres/CHANGELOG.md | 16 ++++++++++++++++ tokio-postgres/Cargo.toml | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 91e78b780..3345a1d43 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,5 +1,21 @@ # Change Log +## v0.7.8 + +## Added + +* Added `keepalives_interval` and `keepalives_retries` config options. +* Added new `SqlState` variants. +* Added more `Debug` impls. +* Added `GenericClient::batch_execute`. +* Added `RowStream::rows_affected`. +* Added the `tcp_user_timeout` config option. + +## Changed + +* Passing an incorrect number of parameters to a query method now returns an error instead of panicking. +* Upgraded `socket2`. + ## v0.7.7 - 2022-08-21 ## Added diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index c29852dec..e5451e2a2 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.7.7" +version = "0.7.8" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From cf9747e3e54f5d0e12deb23ded2d896c4d16de39 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 27 Mar 2023 19:20:24 -0400 Subject: [PATCH 268/420] Add tcp_user_timeout to postgres --- postgres/src/config.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index b541ec846..95c5ea417 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -44,6 +44,9 @@ use tokio_postgres::{Error, Socket}; /// omitted or the empty string. /// * `connect_timeout` - The time limit in seconds applied to each socket-level connection attempt. Note that hostnames /// can resolve to multiple IP addresses, and this limit is applied to each address. Defaults to no timeout. +/// * `tcp_user_timeout` - The time limit that transmitted data may remain unacknowledged before a connection is forcibly closed. +/// This is ignored for Unix domain socket connections. It is only supported on systems where TCP_USER_TIMEOUT is available +/// and will default to the system default if omitted or set to 0; on other systems, it has no effect. /// * `keepalives` - Controls the use of TCP keepalive. A value of 0 disables keepalive and nonzero integers enable it. /// This option is ignored when connecting with Unix sockets. Defaults to on. /// * `keepalives_idle` - The number of seconds of inactivity after which a keepalive message is sent to the server. @@ -256,6 +259,22 @@ impl Config { self.config.get_connect_timeout() } + /// Sets the TCP user timeout. + /// + /// This is ignored for Unix domain socket connections. It is only supported on systems where + /// TCP_USER_TIMEOUT is available and will default to the system default if omitted or set to 0; + /// on other systems, it has no effect. + pub fn tcp_user_timeout(&mut self, tcp_user_timeout: Duration) -> &mut Config { + self.config.tcp_user_timeout(tcp_user_timeout); + self + } + + /// Gets the TCP user timeout, if one has been set with the + /// `user_timeout` method. + pub fn get_tcp_user_timeout(&self) -> Option<&Duration> { + self.config.get_tcp_user_timeout() + } + /// Controls the use of TCP keepalive. /// /// This is ignored for Unix domain socket connections. Defaults to `true`. From 7d5962ef3ff811bbfe54cb069a9d0401cf1d92a5 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 27 Mar 2023 19:24:48 -0400 Subject: [PATCH 269/420] Add RowIter::rows_affected --- postgres/src/row_iter.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/postgres/src/row_iter.rs b/postgres/src/row_iter.rs index 772e9893c..221fdfc68 100644 --- a/postgres/src/row_iter.rs +++ b/postgres/src/row_iter.rs @@ -17,6 +17,13 @@ impl<'a> RowIter<'a> { it: Box::pin(stream), } } + + /// Returns the number of rows affected by the query. + /// + /// This function will return `None` until the iterator has been exhausted. + pub fn rows_affected(&self) -> Option { + self.it.rows_affected() + } } impl FallibleIterator for RowIter<'_> { From 65a68dfa463d4779e709234bbcacbf952f265223 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 27 Mar 2023 19:27:16 -0400 Subject: [PATCH 270/420] Release postgres v0.19.5 --- postgres/CHANGELOG.md | 12 ++++++++++++ postgres/Cargo.toml | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index c467c8b73..b8263a04a 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,5 +1,17 @@ # Change Log +## v0.19.5 - 2023-03-27 + +## Added + +* Added `keepalives_interval` and `keepalives_retries` config options. +* Added the `tcp_user_timeout` config option. +* Added `RowIter::rows_affected`. + +## Changed + +* Passing an incorrect number of parameters to a query method now returns an error instead of panicking. + ## v0.19.4 - 2022-08-21 ## Added diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index e3a8663f2..e0b2a249d 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.19.4" +version = "0.19.5" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -39,7 +39,7 @@ with-time-0_3 = ["tokio-postgres/with-time-0_3"] bytes = "1.0" fallible-iterator = "0.2" futures-util = { version = "0.3.14", features = ["sink"] } -tokio-postgres = { version = "0.7.7", path = "../tokio-postgres" } +tokio-postgres = { version = "0.7.8", path = "../tokio-postgres" } tokio = { version = "1.0", features = ["rt", "time"] } log = "0.4" From f4b181a20180f1853351be53a32865b6209d0ab4 Mon Sep 17 00:00:00 2001 From: jaydenelliott Date: Tue, 28 Mar 2023 22:25:50 +1100 Subject: [PATCH 271/420] Rename_all attribute documentation --- postgres-derive-test/src/enums.rs | 10 +++++----- postgres-derive/src/fromsql.rs | 4 ++-- postgres-derive/src/tosql.rs | 4 ++-- postgres-types/src/lib.rs | 31 +++++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/postgres-derive-test/src/enums.rs b/postgres-derive-test/src/enums.rs index e44f37616..36d428437 100644 --- a/postgres-derive-test/src/enums.rs +++ b/postgres-derive-test/src/enums.rs @@ -58,15 +58,15 @@ fn rename_all_overrides() { #[derive(Debug, ToSql, FromSql, PartialEq)] #[postgres(name = "mood", rename_all = "snake_case")] enum Mood { - Sad, + VerySad, #[postgres(name = "okay")] Ok, - Happy, + VeryHappy, } let mut conn = Client::connect("user=postgres host=localhost port=5433", NoTls).unwrap(); conn.execute( - "CREATE TYPE pg_temp.mood AS ENUM ('sad', 'okay', 'happy')", + "CREATE TYPE pg_temp.mood AS ENUM ('very_sad', 'okay', 'very_happy')", &[], ) .unwrap(); @@ -75,9 +75,9 @@ fn rename_all_overrides() { &mut conn, "mood", &[ - (Mood::Sad, "'sad'"), + (Mood::VerySad, "'very_sad'"), (Mood::Ok, "'okay'"), - (Mood::Happy, "'happy'"), + (Mood::VeryHappy, "'very_happy'"), ], ); } diff --git a/postgres-derive/src/fromsql.rs b/postgres-derive/src/fromsql.rs index 4deb23ed2..a9150411a 100644 --- a/postgres-derive/src/fromsql.rs +++ b/postgres-derive/src/fromsql.rs @@ -17,10 +17,10 @@ use crate::overrides::Overrides; pub fn expand_derive_fromsql(input: DeriveInput) -> Result { let overrides = Overrides::extract(&input.attrs, true)?; - if overrides.name.is_some() && overrides.transparent { + if (overrides.name.is_some() || overrides.rename_all.is_some()) && overrides.transparent { return Err(Error::new_spanned( &input, - "#[postgres(transparent)] is not allowed with #[postgres(name = \"...\")]", + "#[postgres(transparent)] is not allowed with #[postgres(name = \"...\")] or #[postgres(rename_all = \"...\")]", )); } diff --git a/postgres-derive/src/tosql.rs b/postgres-derive/src/tosql.rs index dbeeb16c3..ec7602312 100644 --- a/postgres-derive/src/tosql.rs +++ b/postgres-derive/src/tosql.rs @@ -15,10 +15,10 @@ use crate::overrides::Overrides; pub fn expand_derive_tosql(input: DeriveInput) -> Result { let overrides = Overrides::extract(&input.attrs, true)?; - if overrides.name.is_some() && overrides.transparent { + if (overrides.name.is_some() || overrides.rename_all.is_some()) && overrides.transparent { return Err(Error::new_spanned( &input, - "#[postgres(transparent)] is not allowed with #[postgres(name = \"...\")]", + "#[postgres(transparent)] is not allowed with #[postgres(name = \"...\")] or #[postgres(rename_all = \"...\")]", )); } diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index fa49d99eb..5fca049a7 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -125,6 +125,37 @@ //! Happy, //! } //! ``` +//! +//! Alternatively, the `#[postgres(rename_all = "...")]` attribute can be used to rename all fields or variants +//! with the chosen casing convention. This will not affect the struct or enum's type name. Note that +//! `#[postgres(name = "...")]` takes precendence when used in conjunction with `#[postgres(rename_all = "...")]`: +//! +//! ```rust +//! # #[cfg(feature = "derive")] +//! use postgres_types::{ToSql, FromSql}; +//! +//! # #[cfg(feature = "derive")] +//! #[derive(Debug, ToSql, FromSql)] +//! #[postgres(name = "mood", rename_all = "snake_case")] +//! enum Mood { +//! VerySad, // very_sad +//! #[postgres(name = "ok")] +//! Ok, // ok +//! VeryHappy, // very_happy +//! } +//! ``` +//! +//! The following case conventions are supported: +//! - `"lowercase"` +//! - `"UPPERCASE"` +//! - `"PascalCase"` +//! - `"camelCase"` +//! - `"snake_case"` +//! - `"SCREAMING_SNAKE_CASE"` +//! - `"kebab-case"` +//! - `"SCREAMING-KEBAB-CASE"` +//! - `"Train-Case"` + #![doc(html_root_url = "https://docs.rs/postgres-types/0.2")] #![warn(clippy::all, rust_2018_idioms, missing_docs)] From b19fdd4b7ecab1e30e56f55dc95de8d53f9d14da Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Thu, 30 Mar 2023 19:30:40 -0400 Subject: [PATCH 272/420] Fix postgres-protocol constraint Closes #1012 --- tokio-postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index e5451e2a2..4dc93e3a2 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -53,7 +53,7 @@ parking_lot = "0.12" percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.11" -postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" } +postgres-protocol = { version = "0.6.5", path = "../postgres-protocol" } postgres-types = { version = "0.2.4", path = "../postgres-types" } socket2 = { version = "0.5", features = ["all"] } tokio = { version = "1.27", features = ["io-util"] } From 45d51d708c645f0ebbd3d0dcf5f3eaad3d461916 Mon Sep 17 00:00:00 2001 From: Niklas Hallqvist Date: Tue, 4 Apr 2023 14:27:45 +0200 Subject: [PATCH 273/420] OpenBSD misses some TCP keepalive options --- tokio-postgres/src/keepalive.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/src/keepalive.rs b/tokio-postgres/src/keepalive.rs index 74f453985..24d8d2c0e 100644 --- a/tokio-postgres/src/keepalive.rs +++ b/tokio-postgres/src/keepalive.rs @@ -12,12 +12,12 @@ impl From<&KeepaliveConfig> for TcpKeepalive { fn from(keepalive_config: &KeepaliveConfig) -> Self { let mut tcp_keepalive = Self::new().with_time(keepalive_config.idle); - #[cfg(not(any(target_os = "redox", target_os = "solaris")))] + #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "openbsd")))] if let Some(interval) = keepalive_config.interval { tcp_keepalive = tcp_keepalive.with_interval(interval); } - #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows")))] + #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows", target_os = "openbsd")))] if let Some(retries) = keepalive_config.retries { tcp_keepalive = tcp_keepalive.with_retries(retries); } From e59a16524190db45eead594c61b6a9012ad3a3b9 Mon Sep 17 00:00:00 2001 From: Niklas Hallqvist Date: Tue, 4 Apr 2023 15:43:39 +0200 Subject: [PATCH 274/420] rustfmt --- tokio-postgres/src/keepalive.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tokio-postgres/src/keepalive.rs b/tokio-postgres/src/keepalive.rs index 24d8d2c0e..c409eb0ea 100644 --- a/tokio-postgres/src/keepalive.rs +++ b/tokio-postgres/src/keepalive.rs @@ -17,7 +17,12 @@ impl From<&KeepaliveConfig> for TcpKeepalive { tcp_keepalive = tcp_keepalive.with_interval(interval); } - #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "windows", target_os = "openbsd")))] + #[cfg(not(any( + target_os = "redox", + target_os = "solaris", + target_os = "windows", + target_os = "openbsd" + )))] if let Some(retries) = keepalive_config.retries { tcp_keepalive = tcp_keepalive.with_retries(retries); } From a67fe643a9dc483530ba1df5cf09e3dfdec90c98 Mon Sep 17 00:00:00 2001 From: Basti Ortiz <39114273+BastiDood@users.noreply.github.com> Date: Fri, 7 Apr 2023 21:39:37 +0800 Subject: [PATCH 275/420] refactor(types): simplify `<&str as ToSql>::to_sql` --- postgres-types/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index fa49d99eb..c34fbe66d 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -1012,10 +1012,10 @@ impl ToSql for Vec { impl<'a> ToSql for &'a str { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { - match *ty { - ref ty if ty.name() == "ltree" => types::ltree_to_sql(self, w), - ref ty if ty.name() == "lquery" => types::lquery_to_sql(self, w), - ref ty if ty.name() == "ltxtquery" => types::ltxtquery_to_sql(self, w), + match ty.name() { + "ltree" => types::ltree_to_sql(self, w), + "lquery" => types::lquery_to_sql(self, w), + "ltxtquery" => types::ltxtquery_to_sql(self, w), _ => types::text_to_sql(self, w), } Ok(IsNull::No) From 98abdf9fa25a2e908fd62c5961655e00989fafa2 Mon Sep 17 00:00:00 2001 From: Basti Ortiz <39114273+BastiDood@users.noreply.github.com> Date: Fri, 7 Apr 2023 21:43:25 +0800 Subject: [PATCH 276/420] refactor(types): prefer `matches!` macro for readability --- postgres-types/src/lib.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index c34fbe66d..291e069da 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -1022,18 +1022,10 @@ impl<'a> ToSql for &'a str { } fn accepts(ty: &Type) -> bool { - match *ty { - Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN => true, - ref ty - if (ty.name() == "citext" - || ty.name() == "ltree" - || ty.name() == "lquery" - || ty.name() == "ltxtquery") => - { - true - } - _ => false, - } + matches!( + *ty, + Type::VARCHAR | Type::TEXT | Type::BPCHAR | Type::NAME | Type::UNKNOWN + ) || matches!(ty.name(), "citext" | "ltree" | "lquery" | "ltxtquery") } to_sql_checked!(); From e71335ee43978311b2c1f253afef6c92abdaac88 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 1 May 2023 19:33:49 -0400 Subject: [PATCH 277/420] fix serialization of oidvector --- postgres-types/src/lib.rs | 8 +++++++- tokio-postgres/src/connect_socket.rs | 4 +++- tokio-postgres/tests/test/types/mod.rs | 11 +++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 291e069da..c4c448c4a 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -910,9 +910,15 @@ impl<'a, T: ToSql> ToSql for &'a [T] { _ => panic!("expected array type"), }; + // Arrays are normally one indexed by default but oidvector *requires* zero indexing + let lower_bound = match *ty { + Type::OID_VECTOR => 0, + _ => 1, + }; + let dimension = ArrayDimension { len: downcast(self.len())?, - lower_bound: 1, + lower_bound, }; types::array_to_sql( diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 9b3d31d72..1204ca1ff 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -14,7 +14,9 @@ pub(crate) async fn connect_socket( host: &Host, port: u16, connect_timeout: Option, - tcp_user_timeout: Option, + #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] tcp_user_timeout: Option< + Duration, + >, keepalive_config: Option<&KeepaliveConfig>, ) -> Result { match host { diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index 452d149fe..0f1d38242 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -739,3 +739,14 @@ async fn ltxtquery_any() { ) .await; } + +#[tokio::test] +async fn oidvector() { + test_type( + "oidvector", + // NB: postgres does not support empty oidarrays! All empty arrays are normalized to zero dimensions, but the + // oidvectorrecv function requires exactly one dimension. + &[(Some(vec![0u32, 1, 2]), "ARRAY[0,1,2]"), (None, "NULL")], + ) + .await; +} From d92b3b0a63e7abba41d56cebd06356d1a50db879 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 1 May 2023 19:45:54 -0400 Subject: [PATCH 278/420] Fix int2vector serialization --- postgres-types/src/lib.rs | 4 ++-- tokio-postgres/tests/test/types/mod.rs | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index c4c448c4a..b03c389a9 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -910,9 +910,9 @@ impl<'a, T: ToSql> ToSql for &'a [T] { _ => panic!("expected array type"), }; - // Arrays are normally one indexed by default but oidvector *requires* zero indexing + // Arrays are normally one indexed by default but oidvector and int2vector *require* zero indexing let lower_bound = match *ty { - Type::OID_VECTOR => 0, + Type::OID_VECTOR | Type::INT2_VECTOR => 0, _ => 1, }; diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index 0f1d38242..f1a44da08 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -750,3 +750,14 @@ async fn oidvector() { ) .await; } + +#[tokio::test] +async fn int2vector() { + test_type( + "int2vector", + // NB: postgres does not support empty int2vectors! All empty arrays are normalized to zero dimensions, but the + // oidvectorrecv function requires exactly one dimension. + &[(Some(vec![0i16, 1, 2]), "ARRAY[0,1,2]"), (None, "NULL")], + ) + .await; +} From 80adf0448b95548dabd8354ae6988f801e7a5965 Mon Sep 17 00:00:00 2001 From: Ibiyemi Abiodun Date: Sun, 7 May 2023 13:37:52 -0400 Subject: [PATCH 279/420] allow `BorrowToSql` for non-static `Box` --- postgres-types/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 291e069da..6517b4a95 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -1178,17 +1178,17 @@ impl BorrowToSql for &dyn ToSql { } } -impl sealed::Sealed for Box {} +impl<'a> sealed::Sealed for Box {} -impl BorrowToSql for Box { +impl<'a> BorrowToSql for Box { #[inline] fn borrow_to_sql(&self) -> &dyn ToSql { self.as_ref() } } -impl sealed::Sealed for Box {} -impl BorrowToSql for Box { +impl<'a> sealed::Sealed for Box {} +impl<'a> BorrowToSql for Box { #[inline] fn borrow_to_sql(&self) -> &dyn ToSql { self.as_ref() From 066b466f4443d0d51c6b1d409f3a2c93019ca27e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 7 May 2023 13:48:50 -0400 Subject: [PATCH 280/420] Update ci.yml --- .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 8044b2f47..8e91c6faf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: - run: docker compose up -d - uses: sfackler/actions/rustup@master with: - version: 1.64.0 + version: 1.65.0 - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - uses: actions/cache@v3 From 40954901a422838800a0f99608bf0ab308e5e9aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 May 2023 14:01:30 +0000 Subject: [PATCH 281/420] Update criterion requirement from 0.4 to 0.5 Updates the requirements on [criterion](https://github.com/bheisler/criterion.rs) to permit the latest version. - [Changelog](https://github.com/bheisler/criterion.rs/blob/master/CHANGELOG.md) - [Commits](https://github.com/bheisler/criterion.rs/compare/0.4.0...0.5.0) --- updated-dependencies: - dependency-name: criterion dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- postgres/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index e0b2a249d..044bb91e1 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -45,5 +45,5 @@ tokio = { version = "1.0", features = ["rt", "time"] } log = "0.4" [dev-dependencies] -criterion = "0.4" +criterion = "0.5" tokio = { version = "1.0", features = ["rt-multi-thread"] } diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 4dc93e3a2..b5c6d0ae6 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -61,7 +61,7 @@ tokio-util = { version = "0.7", features = ["codec"] } [dev-dependencies] futures-executor = "0.3" -criterion = "0.4" +criterion = "0.5" env_logger = "0.10" tokio = { version = "1.0", features = [ "macros", From 64bf779f7c91524b820e60226a6b8c8075d2dfa4 Mon Sep 17 00:00:00 2001 From: Zeb Piasecki Date: Sat, 3 Jun 2023 09:18:58 -0400 Subject: [PATCH 282/420] feat: add support for wasm Adds support for compiling to WASM environments that provide JS via wasm-bindgen. Because there's no standardized socket API the caller must provide a connection that implements AsyncRead/AsyncWrite to connect_raw. --- Cargo.toml | 1 + postgres-protocol/Cargo.toml | 3 +++ tokio-postgres/Cargo.toml | 4 +++- tokio-postgres/src/config.rs | 42 ++++++++++++++++++++++++++---------- tokio-postgres/src/lib.rs | 1 + 5 files changed, 39 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4752836a7..80a7739c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "codegen", "postgres", diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index e32211369..1c6422e7d 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -19,3 +19,6 @@ memchr = "2.0" rand = "0.8" sha2 = "0.10" stringprep = "0.1" + +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { version = "0.2.9", features = ["js"] } diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index b5c6d0ae6..af0e6dee0 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -55,10 +55,12 @@ pin-project-lite = "0.2" phf = "0.11" postgres-protocol = { version = "0.6.5", path = "../postgres-protocol" } postgres-types = { version = "0.2.4", path = "../postgres-types" } -socket2 = { version = "0.5", features = ["all"] } tokio = { version = "1.27", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +socket2 = { version = "0.5", features = ["all"] } + [dev-dependencies] futures-executor = "0.3" criterion = "0.5" diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index a8aa7a9f5..2b2be08ef 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -3,6 +3,7 @@ #[cfg(feature = "runtime")] use crate::connect::connect; use crate::connect_raw::connect_raw; +#[cfg(not(target_arch = "wasm32"))] use crate::keepalive::KeepaliveConfig; #[cfg(feature = "runtime")] use crate::tls::MakeTlsConnect; @@ -165,6 +166,7 @@ pub struct Config { pub(crate) connect_timeout: Option, pub(crate) tcp_user_timeout: Option, pub(crate) keepalives: bool, + #[cfg(not(target_arch = "wasm32"))] pub(crate) keepalive_config: KeepaliveConfig, pub(crate) target_session_attrs: TargetSessionAttrs, pub(crate) channel_binding: ChannelBinding, @@ -179,11 +181,6 @@ impl Default for Config { impl Config { /// Creates a new configuration. pub fn new() -> Config { - let keepalive_config = KeepaliveConfig { - idle: Duration::from_secs(2 * 60 * 60), - interval: None, - retries: None, - }; Config { user: None, password: None, @@ -196,7 +193,12 @@ impl Config { connect_timeout: None, tcp_user_timeout: None, keepalives: true, - keepalive_config, + #[cfg(not(target_arch = "wasm32"))] + keepalive_config: KeepaliveConfig { + idle: Duration::from_secs(2 * 60 * 60), + interval: None, + retries: None, + }, target_session_attrs: TargetSessionAttrs::Any, channel_binding: ChannelBinding::Prefer, } @@ -377,6 +379,7 @@ impl Config { /// Sets the amount of idle time before a keepalive packet is sent on the connection. /// /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. Defaults to 2 hours. + #[cfg(not(target_arch = "wasm32"))] pub fn keepalives_idle(&mut self, keepalives_idle: Duration) -> &mut Config { self.keepalive_config.idle = keepalives_idle; self @@ -384,6 +387,7 @@ impl Config { /// Gets the configured amount of idle time before a keepalive packet will /// be sent on the connection. + #[cfg(not(target_arch = "wasm32"))] pub fn get_keepalives_idle(&self) -> Duration { self.keepalive_config.idle } @@ -392,12 +396,14 @@ impl Config { /// On Windows, this sets the value of the tcp_keepalive struct’s keepaliveinterval field. /// /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. + #[cfg(not(target_arch = "wasm32"))] pub fn keepalives_interval(&mut self, keepalives_interval: Duration) -> &mut Config { self.keepalive_config.interval = Some(keepalives_interval); self } /// Gets the time interval between TCP keepalive probes. + #[cfg(not(target_arch = "wasm32"))] pub fn get_keepalives_interval(&self) -> Option { self.keepalive_config.interval } @@ -405,12 +411,14 @@ impl Config { /// Sets the maximum number of TCP keepalive probes that will be sent before dropping a connection. /// /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. + #[cfg(not(target_arch = "wasm32"))] pub fn keepalives_retries(&mut self, keepalives_retries: u32) -> &mut Config { self.keepalive_config.retries = Some(keepalives_retries); self } /// Gets the maximum number of TCP keepalive probes that will be sent before dropping a connection. + #[cfg(not(target_arch = "wasm32"))] pub fn get_keepalives_retries(&self) -> Option { self.keepalive_config.retries } @@ -503,12 +511,14 @@ impl Config { self.tcp_user_timeout(Duration::from_secs(timeout as u64)); } } + #[cfg(not(target_arch = "wasm32"))] "keepalives" => { let keepalives = value .parse::() .map_err(|_| Error::config_parse(Box::new(InvalidValue("keepalives"))))?; self.keepalives(keepalives != 0); } + #[cfg(not(target_arch = "wasm32"))] "keepalives_idle" => { let keepalives_idle = value .parse::() @@ -517,6 +527,7 @@ impl Config { self.keepalives_idle(Duration::from_secs(keepalives_idle as u64)); } } + #[cfg(not(target_arch = "wasm32"))] "keepalives_interval" => { let keepalives_interval = value.parse::().map_err(|_| { Error::config_parse(Box::new(InvalidValue("keepalives_interval"))) @@ -525,6 +536,7 @@ impl Config { self.keepalives_interval(Duration::from_secs(keepalives_interval as u64)); } } + #[cfg(not(target_arch = "wasm32"))] "keepalives_retries" => { let keepalives_retries = value.parse::().map_err(|_| { Error::config_parse(Box::new(InvalidValue("keepalives_retries"))) @@ -614,7 +626,8 @@ impl fmt::Debug for Config { } } - f.debug_struct("Config") + let mut config_dbg = &mut f.debug_struct("Config"); + config_dbg = config_dbg .field("user", &self.user) .field("password", &self.password.as_ref().map(|_| Redaction {})) .field("dbname", &self.dbname) @@ -625,10 +638,17 @@ impl fmt::Debug for Config { .field("port", &self.port) .field("connect_timeout", &self.connect_timeout) .field("tcp_user_timeout", &self.tcp_user_timeout) - .field("keepalives", &self.keepalives) - .field("keepalives_idle", &self.keepalive_config.idle) - .field("keepalives_interval", &self.keepalive_config.interval) - .field("keepalives_retries", &self.keepalive_config.retries) + .field("keepalives", &self.keepalives); + + #[cfg(not(target_arch = "wasm32"))] + { + config_dbg = config_dbg + .field("keepalives_idle", &self.keepalive_config.idle) + .field("keepalives_interval", &self.keepalive_config.interval) + .field("keepalives_retries", &self.keepalive_config.retries); + } + + config_dbg .field("target_session_attrs", &self.target_session_attrs) .field("channel_binding", &self.channel_binding) .finish() diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index a9ecba4f1..2bb410187 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -163,6 +163,7 @@ mod copy_in; mod copy_out; pub mod error; mod generic_client; +#[cfg(not(target_arch = "wasm32"))] mod keepalive; mod maybe_tls_stream; mod portal; From 2230e88533acccf5632b2d43aff315c88a2507a2 Mon Sep 17 00:00:00 2001 From: Zeb Piasecki Date: Sat, 3 Jun 2023 17:32:48 -0400 Subject: [PATCH 283/420] add CI job for checking wasm Adds a CI job for ensuring the tokio-postgres crate builds on the wasm32-unknown-unknown target without the default features. --- .github/workflows/ci.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8e91c6faf..46f97e48f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,6 +47,33 @@ jobs: key: clippy-target-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}y - run: cargo clippy --all --all-targets + check-wasm32: + name: check-wasm32 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: sfackler/actions/rustup@master + - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT + id: rust-version + - run: rustup target add wasm32-unknown-unknown + - uses: actions/cache@v3 + with: + path: ~/.cargo/registry/index + key: index-${{ runner.os }}-${{ github.run_number }} + restore-keys: | + index-${{ runner.os }}- + - run: cargo generate-lockfile + - uses: actions/cache@v3 + with: + path: ~/.cargo/registry/cache + key: registry-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }} + - run: cargo fetch + - uses: actions/cache@v3 + with: + path: target + key: clippy-target-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}y + - run: cargo check --target wasm32-unknown-unknown --manifest-path tokio-postgres/Cargo.toml --no-default-features + test: name: test runs-on: ubuntu-latest From edc7fdecfb9f81b923bfe904edefd41e7076fa8c Mon Sep 17 00:00:00 2001 From: Zeb Piasecki Date: Sun, 4 Jun 2023 13:02:03 -0400 Subject: [PATCH 284/420] gate wasm support behind feature flag --- Cargo.toml | 1 - postgres-protocol/Cargo.toml | 8 +++++--- tokio-postgres/Cargo.toml | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 80a7739c8..4752836a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,4 @@ [workspace] -resolver = "2" members = [ "codegen", "postgres", diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index 1c6422e7d..ad609f6fa 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -8,6 +8,10 @@ license = "MIT/Apache-2.0" repository = "https://github.com/sfackler/rust-postgres" readme = "../README.md" +[features] +default = [] +js = ["getrandom/js"] + [dependencies] base64 = "0.21" byteorder = "1.0" @@ -19,6 +23,4 @@ memchr = "2.0" rand = "0.8" sha2 = "0.10" stringprep = "0.1" - -[target.'cfg(target_arch = "wasm32")'.dependencies] -getrandom = { version = "0.2.9", features = ["js"] } +getrandom = { version = "0.2", optional = true } diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index af0e6dee0..12d8a66fd 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -40,6 +40,7 @@ with-uuid-0_8 = ["postgres-types/with-uuid-0_8"] with-uuid-1 = ["postgres-types/with-uuid-1"] with-time-0_2 = ["postgres-types/with-time-0_2"] with-time-0_3 = ["postgres-types/with-time-0_3"] +js = ["postgres-protocol/js"] [dependencies] async-trait = "0.1" From 1f8fb7a16c131ed50a46fc139838327e8a604775 Mon Sep 17 00:00:00 2001 From: Zeb Piasecki Date: Wed, 7 Jun 2023 21:17:54 -0400 Subject: [PATCH 285/420] ignore dev deps in wasm ci --- .github/workflows/ci.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 46f97e48f..99cf652d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v3 - uses: sfackler/actions/rustup@master - uses: sfackler/actions/rustfmt@master - + clippy: name: clippy runs-on: ubuntu-latest @@ -72,7 +72,12 @@ jobs: with: path: target key: clippy-target-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}y - - run: cargo check --target wasm32-unknown-unknown --manifest-path tokio-postgres/Cargo.toml --no-default-features + - run: | + # Hack: wasm support currently relies on not having tokio with features like socket enabled. With resolver 1 + # dev dependencies can add unwanted dependencies to the build, so we'll hackily disable them for this check. + + sed -i 's/\[dev-dependencies]/[ignore-dependencies]/g' ./tokio-postgres/Cargo.toml + cargo check --target wasm32-unknown-unknown --manifest-path tokio-postgres/Cargo.toml --no-default-features test: name: test From 635bac4665d4a744a523e6d843f67ffed33b6cff Mon Sep 17 00:00:00 2001 From: Zeb Piasecki Date: Fri, 9 Jun 2023 11:15:06 -0400 Subject: [PATCH 286/420] specify js feature for wasm 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 99cf652d2..0064369c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,7 +77,7 @@ jobs: # dev dependencies can add unwanted dependencies to the build, so we'll hackily disable them for this check. sed -i 's/\[dev-dependencies]/[ignore-dependencies]/g' ./tokio-postgres/Cargo.toml - cargo check --target wasm32-unknown-unknown --manifest-path tokio-postgres/Cargo.toml --no-default-features + cargo check --target wasm32-unknown-unknown --manifest-path tokio-postgres/Cargo.toml --no-default-features --features js test: name: test From 6f19bb9000bd5e53cd7613f0f96a24c3657533b6 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 10 Jun 2023 10:21:34 -0400 Subject: [PATCH 287/420] clean up wasm32 test --- .github/workflows/ci.yml | 9 ++------- Cargo.toml | 1 + 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0064369c9..ebe0f600f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,13 +71,8 @@ jobs: - uses: actions/cache@v3 with: path: target - key: clippy-target-${{ runner.os }}-${{ steps.rust-version.outputs.version }}-${{ hashFiles('Cargo.lock') }}y - - run: | - # Hack: wasm support currently relies on not having tokio with features like socket enabled. With resolver 1 - # dev dependencies can add unwanted dependencies to the build, so we'll hackily disable them for this check. - - sed -i 's/\[dev-dependencies]/[ignore-dependencies]/g' ./tokio-postgres/Cargo.toml - cargo check --target wasm32-unknown-unknown --manifest-path tokio-postgres/Cargo.toml --no-default-features --features js + 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 test: name: test diff --git a/Cargo.toml b/Cargo.toml index 4752836a7..16e3739dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "postgres-types", "tokio-postgres", ] +resolver = "2" [profile.release] debug = 2 From 258fe68f193b7951e20f244ecbbf664d7629f0eb Mon Sep 17 00:00:00 2001 From: Vinicius Hirschle Date: Sat, 29 Apr 2023 21:52:01 -0300 Subject: [PATCH 288/420] feat(derive): add `#[postgres(allow_mismatch)]` --- .../compile-fail/invalid-allow-mismatch.rs | 31 ++++++++ .../invalid-allow-mismatch.stderr | 43 +++++++++++ postgres-derive-test/src/enums.rs | 72 ++++++++++++++++++- postgres-derive/src/accepts.rs | 42 ++++++----- postgres-derive/src/fromsql.rs | 22 +++++- postgres-derive/src/overrides.rs | 22 +++++- postgres-derive/src/tosql.rs | 22 +++++- postgres-types/src/lib.rs | 23 +++++- 8 files changed, 250 insertions(+), 27 deletions(-) create mode 100644 postgres-derive-test/src/compile-fail/invalid-allow-mismatch.rs create mode 100644 postgres-derive-test/src/compile-fail/invalid-allow-mismatch.stderr diff --git a/postgres-derive-test/src/compile-fail/invalid-allow-mismatch.rs b/postgres-derive-test/src/compile-fail/invalid-allow-mismatch.rs new file mode 100644 index 000000000..52d0ba8f6 --- /dev/null +++ b/postgres-derive-test/src/compile-fail/invalid-allow-mismatch.rs @@ -0,0 +1,31 @@ +use postgres_types::{FromSql, ToSql}; + +#[derive(ToSql, Debug)] +#[postgres(allow_mismatch)] +struct ToSqlAllowMismatchStruct { + a: i32, +} + +#[derive(FromSql, Debug)] +#[postgres(allow_mismatch)] +struct FromSqlAllowMismatchStruct { + a: i32, +} + +#[derive(ToSql, Debug)] +#[postgres(allow_mismatch)] +struct ToSqlAllowMismatchTupleStruct(i32, i32); + +#[derive(FromSql, Debug)] +#[postgres(allow_mismatch)] +struct FromSqlAllowMismatchTupleStruct(i32, i32); + +#[derive(FromSql, Debug)] +#[postgres(transparent, allow_mismatch)] +struct TransparentFromSqlAllowMismatchStruct(i32); + +#[derive(FromSql, Debug)] +#[postgres(allow_mismatch, transparent)] +struct AllowMismatchFromSqlTransparentStruct(i32); + +fn main() {} diff --git a/postgres-derive-test/src/compile-fail/invalid-allow-mismatch.stderr b/postgres-derive-test/src/compile-fail/invalid-allow-mismatch.stderr new file mode 100644 index 000000000..a8e573248 --- /dev/null +++ b/postgres-derive-test/src/compile-fail/invalid-allow-mismatch.stderr @@ -0,0 +1,43 @@ +error: #[postgres(allow_mismatch)] may only be applied to enums + --> src/compile-fail/invalid-allow-mismatch.rs:4:1 + | +4 | / #[postgres(allow_mismatch)] +5 | | struct ToSqlAllowMismatchStruct { +6 | | a: i32, +7 | | } + | |_^ + +error: #[postgres(allow_mismatch)] may only be applied to enums + --> src/compile-fail/invalid-allow-mismatch.rs:10:1 + | +10 | / #[postgres(allow_mismatch)] +11 | | struct FromSqlAllowMismatchStruct { +12 | | a: i32, +13 | | } + | |_^ + +error: #[postgres(allow_mismatch)] may only be applied to enums + --> src/compile-fail/invalid-allow-mismatch.rs:16:1 + | +16 | / #[postgres(allow_mismatch)] +17 | | struct ToSqlAllowMismatchTupleStruct(i32, i32); + | |_______________________________________________^ + +error: #[postgres(allow_mismatch)] may only be applied to enums + --> src/compile-fail/invalid-allow-mismatch.rs:20:1 + | +20 | / #[postgres(allow_mismatch)] +21 | | struct FromSqlAllowMismatchTupleStruct(i32, i32); + | |_________________________________________________^ + +error: #[postgres(transparent)] is not allowed with #[postgres(allow_mismatch)] + --> src/compile-fail/invalid-allow-mismatch.rs:24:25 + | +24 | #[postgres(transparent, allow_mismatch)] + | ^^^^^^^^^^^^^^ + +error: #[postgres(allow_mismatch)] is not allowed with #[postgres(transparent)] + --> src/compile-fail/invalid-allow-mismatch.rs:28:28 + | +28 | #[postgres(allow_mismatch, transparent)] + | ^^^^^^^^^^^ diff --git a/postgres-derive-test/src/enums.rs b/postgres-derive-test/src/enums.rs index 36d428437..f3e6c488c 100644 --- a/postgres-derive-test/src/enums.rs +++ b/postgres-derive-test/src/enums.rs @@ -1,5 +1,5 @@ use crate::test_type; -use postgres::{Client, NoTls}; +use postgres::{error::DbError, Client, NoTls}; use postgres_types::{FromSql, ToSql, WrongType}; use std::error::Error; @@ -131,3 +131,73 @@ fn missing_variant() { let err = conn.execute("SELECT $1::foo", &[&Foo::Bar]).unwrap_err(); assert!(err.source().unwrap().is::()); } + +#[test] +fn allow_mismatch_enums() { + #[derive(Debug, ToSql, FromSql, PartialEq)] + #[postgres(allow_mismatch)] + enum Foo { + Bar, + } + + let mut conn = Client::connect("user=postgres host=localhost port=5433", NoTls).unwrap(); + conn.execute("CREATE TYPE pg_temp.\"Foo\" AS ENUM ('Bar', 'Baz')", &[]) + .unwrap(); + + let row = conn.query_one("SELECT $1::\"Foo\"", &[&Foo::Bar]).unwrap(); + assert_eq!(row.get::<_, Foo>(0), Foo::Bar); +} + +#[test] +fn missing_enum_variant() { + #[derive(Debug, ToSql, FromSql, PartialEq)] + #[postgres(allow_mismatch)] + enum Foo { + Bar, + Buz, + } + + let mut conn = Client::connect("user=postgres host=localhost port=5433", NoTls).unwrap(); + conn.execute("CREATE TYPE pg_temp.\"Foo\" AS ENUM ('Bar', 'Baz')", &[]) + .unwrap(); + + let err = conn + .query_one("SELECT $1::\"Foo\"", &[&Foo::Buz]) + .unwrap_err(); + assert!(err.source().unwrap().is::()); +} + +#[test] +fn allow_mismatch_and_renaming() { + #[derive(Debug, ToSql, FromSql, PartialEq)] + #[postgres(name = "foo", allow_mismatch)] + enum Foo { + #[postgres(name = "bar")] + Bar, + #[postgres(name = "buz")] + Buz, + } + + let mut conn = Client::connect("user=postgres host=localhost port=5433", NoTls).unwrap(); + conn.execute("CREATE TYPE pg_temp.foo AS ENUM ('bar', 'baz', 'buz')", &[]) + .unwrap(); + + let row = conn.query_one("SELECT $1::foo", &[&Foo::Buz]).unwrap(); + assert_eq!(row.get::<_, Foo>(0), Foo::Buz); +} + +#[test] +fn wrong_name_and_allow_mismatch() { + #[derive(Debug, ToSql, FromSql, PartialEq)] + #[postgres(allow_mismatch)] + enum Foo { + Bar, + } + + let mut conn = Client::connect("user=postgres host=localhost port=5433", NoTls).unwrap(); + conn.execute("CREATE TYPE pg_temp.foo AS ENUM ('Bar', 'Baz')", &[]) + .unwrap(); + + let err = conn.query_one("SELECT $1::foo", &[&Foo::Bar]).unwrap_err(); + assert!(err.source().unwrap().is::()); +} diff --git a/postgres-derive/src/accepts.rs b/postgres-derive/src/accepts.rs index 63473863a..a68538dcc 100644 --- a/postgres-derive/src/accepts.rs +++ b/postgres-derive/src/accepts.rs @@ -31,31 +31,37 @@ pub fn domain_body(name: &str, field: &syn::Field) -> TokenStream { } } -pub fn enum_body(name: &str, variants: &[Variant]) -> TokenStream { +pub fn enum_body(name: &str, variants: &[Variant], allow_mismatch: bool) -> TokenStream { let num_variants = variants.len(); let variant_names = variants.iter().map(|v| &v.name); - quote! { - if type_.name() != #name { - return false; + if allow_mismatch { + quote! { + type_.name() == #name } + } else { + quote! { + if type_.name() != #name { + return false; + } - match *type_.kind() { - ::postgres_types::Kind::Enum(ref variants) => { - if variants.len() != #num_variants { - return false; - } - - variants.iter().all(|v| { - match &**v { - #( - #variant_names => true, - )* - _ => false, + match *type_.kind() { + ::postgres_types::Kind::Enum(ref variants) => { + if variants.len() != #num_variants { + return false; } - }) + + variants.iter().all(|v| { + match &**v { + #( + #variant_names => true, + )* + _ => false, + } + }) + } + _ => false, } - _ => false, } } } diff --git a/postgres-derive/src/fromsql.rs b/postgres-derive/src/fromsql.rs index a9150411a..d3ac47f4f 100644 --- a/postgres-derive/src/fromsql.rs +++ b/postgres-derive/src/fromsql.rs @@ -48,6 +48,26 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result { )) } } + } else if overrides.allow_mismatch { + match input.data { + Data::Enum(ref data) => { + let variants = data + .variants + .iter() + .map(|variant| Variant::parse(variant, overrides.rename_all)) + .collect::, _>>()?; + ( + accepts::enum_body(&name, &variants, overrides.allow_mismatch), + enum_body(&input.ident, &variants), + ) + } + _ => { + return Err(Error::new_spanned( + input, + "#[postgres(allow_mismatch)] may only be applied to enums", + )); + } + } } else { match input.data { Data::Enum(ref data) => { @@ -57,7 +77,7 @@ pub fn expand_derive_fromsql(input: DeriveInput) -> Result { .map(|variant| Variant::parse(variant, overrides.rename_all)) .collect::, _>>()?; ( - accepts::enum_body(&name, &variants), + accepts::enum_body(&name, &variants, overrides.allow_mismatch), enum_body(&input.ident, &variants), ) } diff --git a/postgres-derive/src/overrides.rs b/postgres-derive/src/overrides.rs index 99faeebb7..d50550bee 100644 --- a/postgres-derive/src/overrides.rs +++ b/postgres-derive/src/overrides.rs @@ -7,6 +7,7 @@ pub struct Overrides { pub name: Option, pub rename_all: Option, pub transparent: bool, + pub allow_mismatch: bool, } impl Overrides { @@ -15,6 +16,7 @@ impl Overrides { name: None, rename_all: None, transparent: false, + allow_mismatch: false, }; for attr in attrs { @@ -74,11 +76,25 @@ impl Overrides { } } Meta::Path(path) => { - if !path.is_ident("transparent") { + if path.is_ident("transparent") { + if overrides.allow_mismatch { + return Err(Error::new_spanned( + path, + "#[postgres(allow_mismatch)] is not allowed with #[postgres(transparent)]", + )); + } + overrides.transparent = true; + } else if path.is_ident("allow_mismatch") { + if overrides.transparent { + return Err(Error::new_spanned( + path, + "#[postgres(transparent)] is not allowed with #[postgres(allow_mismatch)]", + )); + } + overrides.allow_mismatch = true; + } else { return Err(Error::new_spanned(path, "unknown override")); } - - overrides.transparent = true; } bad => return Err(Error::new_spanned(bad, "unknown attribute")), } diff --git a/postgres-derive/src/tosql.rs b/postgres-derive/src/tosql.rs index ec7602312..81d4834bf 100644 --- a/postgres-derive/src/tosql.rs +++ b/postgres-derive/src/tosql.rs @@ -44,6 +44,26 @@ pub fn expand_derive_tosql(input: DeriveInput) -> Result { )); } } + } else if overrides.allow_mismatch { + match input.data { + Data::Enum(ref data) => { + let variants = data + .variants + .iter() + .map(|variant| Variant::parse(variant, overrides.rename_all)) + .collect::, _>>()?; + ( + accepts::enum_body(&name, &variants, overrides.allow_mismatch), + enum_body(&input.ident, &variants), + ) + } + _ => { + return Err(Error::new_spanned( + input, + "#[postgres(allow_mismatch)] may only be applied to enums", + )); + } + } } else { match input.data { Data::Enum(ref data) => { @@ -53,7 +73,7 @@ pub fn expand_derive_tosql(input: DeriveInput) -> Result { .map(|variant| Variant::parse(variant, overrides.rename_all)) .collect::, _>>()?; ( - accepts::enum_body(&name, &variants), + accepts::enum_body(&name, &variants, overrides.allow_mismatch), enum_body(&input.ident, &variants), ) } diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index edd723977..cb82e2f93 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -138,7 +138,6 @@ //! #[derive(Debug, ToSql, FromSql)] //! #[postgres(name = "mood", rename_all = "snake_case")] //! enum Mood { -//! VerySad, // very_sad //! #[postgres(name = "ok")] //! Ok, // ok //! VeryHappy, // very_happy @@ -155,10 +154,28 @@ //! - `"kebab-case"` //! - `"SCREAMING-KEBAB-CASE"` //! - `"Train-Case"` - +//! +//! ## Allowing Enum Mismatches +//! +//! By default the generated implementation of [`ToSql`] & [`FromSql`] for enums will require an exact match of the enum +//! variants between the Rust and Postgres types. +//! To allow mismatches, the `#[postgres(allow_mismatch)]` attribute can be used on the enum definition: +//! +//! ```sql +//! CREATE TYPE mood AS ENUM ( +//! 'Sad', +//! 'Ok', +//! 'Happy' +//! ); +//! ``` +//! #[postgres(allow_mismatch)] +//! enum Mood { +//! Happy, +//! Meh, +//! } +//! ``` #![doc(html_root_url = "https://docs.rs/postgres-types/0.2")] #![warn(clippy::all, rust_2018_idioms, missing_docs)] - use fallible_iterator::FallibleIterator; use postgres_protocol::types::{self, ArrayDimension}; use std::any::type_name; From b09e9cc6426728a9df665992a6a1e8cb2c4afbec Mon Sep 17 00:00:00 2001 From: Andrew Baxter Date: Thu, 20 Jul 2023 22:54:19 +0900 Subject: [PATCH 289/420] Add to_sql for bytes Cow as well --- postgres-types/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index edd723977..34c8cc0b8 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -1035,6 +1035,18 @@ impl ToSql for Box<[T]> { to_sql_checked!(); } +impl<'a> ToSql for Cow<'a, [u8]> { + fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { + <&str as ToSql>::to_sql(&self.as_ref(), ty, w) + } + + fn accepts(ty: &Type) -> bool { + <&[u8] as ToSql>::accepts(ty) + } + + to_sql_checked!(); +} + impl ToSql for Vec { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { <&[u8] as ToSql>::to_sql(&&**self, ty, w) From 34c8dc9d1957f6b663c4236217ec7134ad1d3c5b Mon Sep 17 00:00:00 2001 From: andrew <> Date: Thu, 20 Jul 2023 23:30:27 +0900 Subject: [PATCH 290/420] Fixes --- 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 34c8cc0b8..1f56c468f 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -1037,7 +1037,7 @@ impl ToSql for Box<[T]> { impl<'a> ToSql for Cow<'a, [u8]> { fn to_sql(&self, ty: &Type, w: &mut BytesMut) -> Result> { - <&str as ToSql>::to_sql(&self.as_ref(), ty, w) + <&[u8] as ToSql>::to_sql(&self.as_ref(), ty, w) } fn accepts(ty: &Type) -> bool { From f7a264473d8ba78a280f1fe173ecb9f3662be7f3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 22 Jul 2023 20:40:47 -0400 Subject: [PATCH 291/420] align hostaddr tls behavior with documentation --- tokio-postgres/src/cancel_query.rs | 14 +++++--------- tokio-postgres/src/cancel_query_raw.rs | 2 +- tokio-postgres/src/cancel_token.rs | 2 +- tokio-postgres/src/client.rs | 1 + tokio-postgres/src/config.rs | 6 +++--- tokio-postgres/src/connect.rs | 25 ++++++++++++++----------- tokio-postgres/src/connect_raw.rs | 2 +- tokio-postgres/src/connect_tls.rs | 9 +++++++-- 8 files changed, 33 insertions(+), 28 deletions(-) diff --git a/tokio-postgres/src/cancel_query.rs b/tokio-postgres/src/cancel_query.rs index d869b5824..8e35a4224 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::{Host, SslMode}; +use crate::config::SslMode; use crate::tls::MakeTlsConnect; use crate::{cancel_query_raw, connect_socket, Error, Socket}; use std::io; @@ -24,14 +24,10 @@ where } }; - let hostname = match &config.host { - Host::Tcp(host) => &**host, - // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter - #[cfg(unix)] - Host::Unix(_) => "", - }; - let tls = tls - .make_tls_connect(hostname) + let tls = config + .hostname + .map(|s| tls.make_tls_connect(&s)) + .transpose() .map_err(|e| Error::tls(e.into()))?; let socket = connect_socket::connect_socket( diff --git a/tokio-postgres/src/cancel_query_raw.rs b/tokio-postgres/src/cancel_query_raw.rs index c89dc581f..cae887183 100644 --- a/tokio-postgres/src/cancel_query_raw.rs +++ b/tokio-postgres/src/cancel_query_raw.rs @@ -8,7 +8,7 @@ use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; pub async fn cancel_query_raw( stream: S, mode: SslMode, - tls: T, + tls: Option, process_id: i32, secret_key: i32, ) -> Result<(), Error> diff --git a/tokio-postgres/src/cancel_token.rs b/tokio-postgres/src/cancel_token.rs index d048a3c82..9671de726 100644 --- a/tokio-postgres/src/cancel_token.rs +++ b/tokio-postgres/src/cancel_token.rs @@ -54,7 +54,7 @@ impl CancelToken { cancel_query_raw::cancel_query_raw( stream, self.ssl_mode, - tls, + Some(tls), self.process_id, self.secret_key, ) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 8b7df4e87..ac486813e 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -154,6 +154,7 @@ impl InnerClient { #[derive(Clone)] pub(crate) struct SocketConfig { pub host: Host, + pub hostname: Option, pub port: u16, pub connect_timeout: Option, pub tcp_user_timeout: Option, diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index b18e3b8af..c88c5ff35 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -97,9 +97,9 @@ pub enum Host { /// * `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, -/// - or if host specifies an IP address, that value will be used directly. +/// or if host specifies an IP address, that value will be used directly. /// Using `hostaddr` allows the application to avoid a host name look-up, which might be important in applications -/// with time constraints. However, a host name is required for verify-full SSL certificate verification. +/// with time constraints. However, a host name is required for TLS certificate verification. /// Specifically: /// * If `hostaddr` is specified without `host`, the value for `hostaddr` gives the server network address. /// The connection attempt will fail if the authentication method requires a host name; @@ -645,7 +645,7 @@ impl Config { S: AsyncRead + AsyncWrite + Unpin, T: TlsConnect, { - connect_raw(stream, tls, self).await + connect_raw(stream, Some(tls), self).await } } diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 32a0a76b9..abb1a0118 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -52,16 +52,17 @@ where .unwrap_or(5432); // The value of host is used as the hostname for TLS validation, - // if it's not present, use the value of hostaddr. let hostname = match host { - Some(Host::Tcp(host)) => host.clone(), + Some(Host::Tcp(host)) => Some(host.clone()), // postgres doesn't support TLS over unix sockets, so the choice here doesn't matter #[cfg(unix)] - Some(Host::Unix(_)) => "".to_string(), - None => hostaddr.map_or("".to_string(), |ipaddr| ipaddr.to_string()), + Some(Host::Unix(_)) => None, + None => None, }; - let tls = tls - .make_tls_connect(&hostname) + let tls = hostname + .as_ref() + .map(|s| tls.make_tls_connect(s)) + .transpose() .map_err(|e| Error::tls(e.into()))?; // Try to use the value of hostaddr to establish the TCP connection, @@ -78,7 +79,7 @@ where } }; - match connect_once(&addr, port, tls, config).await { + match connect_once(addr, hostname, port, tls, config).await { Ok((client, connection)) => return Ok((client, connection)), Err(e) => error = Some(e), } @@ -88,16 +89,17 @@ where } async fn connect_once( - host: &Host, + host: Host, + hostname: Option, port: u16, - tls: T, + tls: Option, config: &Config, ) -> Result<(Client, Connection), Error> where T: TlsConnect, { let socket = connect_socket( - host, + &host, port, config.connect_timeout, config.tcp_user_timeout, @@ -151,7 +153,8 @@ where } client.set_socket_config(SocketConfig { - host: host.clone(), + host, + hostname, port, connect_timeout: config.connect_timeout, tcp_user_timeout: config.tcp_user_timeout, diff --git a/tokio-postgres/src/connect_raw.rs b/tokio-postgres/src/connect_raw.rs index d97636221..2db6a66b9 100644 --- a/tokio-postgres/src/connect_raw.rs +++ b/tokio-postgres/src/connect_raw.rs @@ -80,7 +80,7 @@ where pub async fn connect_raw( stream: S, - tls: T, + tls: Option, config: &Config, ) -> Result<(Client, Connection), Error> where diff --git a/tokio-postgres/src/connect_tls.rs b/tokio-postgres/src/connect_tls.rs index 5ef21ac5c..d75dcde90 100644 --- a/tokio-postgres/src/connect_tls.rs +++ b/tokio-postgres/src/connect_tls.rs @@ -10,7 +10,7 @@ use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; pub async fn connect_tls( mut stream: S, mode: SslMode, - tls: T, + tls: Option, ) -> Result, Error> where S: AsyncRead + AsyncWrite + Unpin, @@ -18,7 +18,11 @@ where { match mode { SslMode::Disable => return Ok(MaybeTlsStream::Raw(stream)), - SslMode::Prefer if !tls.can_connect(ForcePrivateApi) => { + SslMode::Prefer + if tls + .as_ref() + .map_or(false, |tls| !tls.can_connect(ForcePrivateApi)) => + { return Ok(MaybeTlsStream::Raw(stream)) } SslMode::Prefer | SslMode::Require => {} @@ -40,6 +44,7 @@ where } let stream = tls + .ok_or_else(|| Error::tls("no hostname provided for TLS handshake".into()))? .connect(stream) .await .map_err(|e| Error::tls(e.into()))?; From b57574598ec0985d9b471144fe038886b6d8b92a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 22 Jul 2023 21:09:08 -0400 Subject: [PATCH 292/420] fix test --- tokio-postgres/src/cancel_query.rs | 10 +++++----- tokio-postgres/src/cancel_query_raw.rs | 5 +++-- tokio-postgres/src/cancel_token.rs | 3 ++- tokio-postgres/src/config.rs | 2 +- tokio-postgres/src/connect.rs | 11 +++++------ tokio-postgres/src/connect_raw.rs | 5 +++-- tokio-postgres/src/connect_tls.rs | 14 +++++++------- 7 files changed, 26 insertions(+), 24 deletions(-) diff --git a/tokio-postgres/src/cancel_query.rs b/tokio-postgres/src/cancel_query.rs index 8e35a4224..4a7766d60 100644 --- a/tokio-postgres/src/cancel_query.rs +++ b/tokio-postgres/src/cancel_query.rs @@ -24,11 +24,10 @@ where } }; - let tls = config - .hostname - .map(|s| tls.make_tls_connect(&s)) - .transpose() + let tls = tls + .make_tls_connect(config.hostname.as_deref().unwrap_or("")) .map_err(|e| Error::tls(e.into()))?; + let has_hostname = config.hostname.is_some(); let socket = connect_socket::connect_socket( &config.host, @@ -39,5 +38,6 @@ where ) .await?; - cancel_query_raw::cancel_query_raw(socket, ssl_mode, tls, process_id, secret_key).await + cancel_query_raw::cancel_query_raw(socket, ssl_mode, 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 cae887183..41aafe7d9 100644 --- a/tokio-postgres/src/cancel_query_raw.rs +++ b/tokio-postgres/src/cancel_query_raw.rs @@ -8,7 +8,8 @@ use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt}; pub async fn cancel_query_raw( stream: S, mode: SslMode, - tls: Option, + tls: T, + has_hostname: bool, process_id: i32, secret_key: i32, ) -> Result<(), Error> @@ -16,7 +17,7 @@ where S: AsyncRead + AsyncWrite + Unpin, T: TlsConnect, { - let mut stream = connect_tls::connect_tls(stream, mode, tls).await?; + let mut stream = connect_tls::connect_tls(stream, mode, 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 9671de726..c925ce0ca 100644 --- a/tokio-postgres/src/cancel_token.rs +++ b/tokio-postgres/src/cancel_token.rs @@ -54,7 +54,8 @@ impl CancelToken { cancel_query_raw::cancel_query_raw( stream, self.ssl_mode, - Some(tls), + tls, + true, self.process_id, self.secret_key, ) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index c88c5ff35..a7fa19312 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -645,7 +645,7 @@ impl Config { S: AsyncRead + AsyncWrite + Unpin, T: TlsConnect, { - connect_raw(stream, Some(tls), self).await + connect_raw(stream, tls, true, self).await } } diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index abb1a0118..441ad1238 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -59,10 +59,8 @@ where Some(Host::Unix(_)) => None, None => None, }; - let tls = hostname - .as_ref() - .map(|s| tls.make_tls_connect(s)) - .transpose() + let tls = tls + .make_tls_connect(hostname.as_deref().unwrap_or("")) .map_err(|e| Error::tls(e.into()))?; // Try to use the value of hostaddr to establish the TCP connection, @@ -92,7 +90,7 @@ async fn connect_once( host: Host, hostname: Option, port: u16, - tls: Option, + tls: T, config: &Config, ) -> Result<(Client, Connection), Error> where @@ -110,7 +108,8 @@ where }, ) .await?; - let (mut client, mut connection) = connect_raw(socket, tls, config).await?; + let has_hostname = hostname.is_some(); + let (mut client, mut connection) = connect_raw(socket, tls, has_hostname, config).await?; if let TargetSessionAttrs::ReadWrite = config.target_session_attrs { let rows = client.simple_query_raw("SHOW transaction_read_only"); diff --git a/tokio-postgres/src/connect_raw.rs b/tokio-postgres/src/connect_raw.rs index 2db6a66b9..254ca9f0c 100644 --- a/tokio-postgres/src/connect_raw.rs +++ b/tokio-postgres/src/connect_raw.rs @@ -80,14 +80,15 @@ where pub async fn connect_raw( stream: S, - tls: Option, + tls: T, + has_hostname: bool, config: &Config, ) -> Result<(Client, Connection), Error> where S: AsyncRead + AsyncWrite + Unpin, T: TlsConnect, { - let stream = connect_tls(stream, config.ssl_mode, tls).await?; + let stream = connect_tls(stream, config.ssl_mode, tls, has_hostname).await?; let mut stream = StartupStream { inner: Framed::new(stream, PostgresCodec), diff --git a/tokio-postgres/src/connect_tls.rs b/tokio-postgres/src/connect_tls.rs index d75dcde90..2b1229125 100644 --- a/tokio-postgres/src/connect_tls.rs +++ b/tokio-postgres/src/connect_tls.rs @@ -10,7 +10,8 @@ use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; pub async fn connect_tls( mut stream: S, mode: SslMode, - tls: Option, + tls: T, + has_hostname: bool, ) -> Result, Error> where S: AsyncRead + AsyncWrite + Unpin, @@ -18,11 +19,7 @@ where { match mode { SslMode::Disable => return Ok(MaybeTlsStream::Raw(stream)), - SslMode::Prefer - if tls - .as_ref() - .map_or(false, |tls| !tls.can_connect(ForcePrivateApi)) => - { + SslMode::Prefer if !tls.can_connect(ForcePrivateApi) => { return Ok(MaybeTlsStream::Raw(stream)) } SslMode::Prefer | SslMode::Require => {} @@ -43,8 +40,11 @@ where } } + if !has_hostname { + return Err(Error::tls("no hostname provided for TLS handshake".into())); + } + let stream = tls - .ok_or_else(|| Error::tls("no hostname provided for TLS handshake".into()))? .connect(stream) .await .map_err(|e| Error::tls(e.into()))?; From 3346858dd26b20d63eaae8f3db86773b6896b4c3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 23 Jul 2023 09:52:56 -0400 Subject: [PATCH 293/420] Implement load balancing --- tokio-postgres/Cargo.toml | 1 + tokio-postgres/src/cancel_query.rs | 2 +- tokio-postgres/src/client.rs | 14 ++++- tokio-postgres/src/config.rs | 43 +++++++++++++ tokio-postgres/src/connect.rs | 93 +++++++++++++++++++++------- tokio-postgres/src/connect_socket.rs | 65 +++++++------------ 6 files changed, 149 insertions(+), 69 deletions(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 12d8a66fd..12c4bd689 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -58,6 +58,7 @@ postgres-protocol = { version = "0.6.5", path = "../postgres-protocol" } postgres-types = { version = "0.2.4", path = "../postgres-types" } tokio = { version = "1.27", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } +rand = "0.8.5" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] socket2 = { version = "0.5", features = ["all"] } diff --git a/tokio-postgres/src/cancel_query.rs b/tokio-postgres/src/cancel_query.rs index 4a7766d60..078d4b8b6 100644 --- a/tokio-postgres/src/cancel_query.rs +++ b/tokio-postgres/src/cancel_query.rs @@ -30,7 +30,7 @@ where let has_hostname = config.hostname.is_some(); let socket = connect_socket::connect_socket( - &config.host, + &config.addr, config.port, config.connect_timeout, config.tcp_user_timeout, diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index ac486813e..2185d2146 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -1,6 +1,4 @@ use crate::codec::{BackendMessages, FrontendMessage}; -#[cfg(feature = "runtime")] -use crate::config::Host; use crate::config::SslMode; use crate::connection::{Request, RequestMessages}; use crate::copy_out::CopyOutStream; @@ -27,6 +25,8 @@ use postgres_protocol::message::{backend::Message, frontend}; use postgres_types::BorrowToSql; use std::collections::HashMap; use std::fmt; +use std::net::IpAddr; +use std::path::PathBuf; use std::sync::Arc; use std::task::{Context, Poll}; #[cfg(feature = "runtime")] @@ -153,7 +153,7 @@ impl InnerClient { #[cfg(feature = "runtime")] #[derive(Clone)] pub(crate) struct SocketConfig { - pub host: Host, + pub addr: Addr, pub hostname: Option, pub port: u16, pub connect_timeout: Option, @@ -161,6 +161,14 @@ pub(crate) struct SocketConfig { pub keepalive: Option, } +#[cfg(feature = "runtime")] +#[derive(Clone)] +pub(crate) enum Addr { + Tcp(IpAddr), + #[cfg(unix)] + Unix(PathBuf), +} + /// An asynchronous PostgreSQL client. /// /// The client is one half of what is returned when a connection is established. Users interact with the database diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index a7fa19312..87d77d35a 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -60,6 +60,16 @@ pub enum ChannelBinding { Require, } +/// Load balancing configuration. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[non_exhaustive] +pub enum LoadBalanceHosts { + /// Make connection attempts to hosts in the order provided. + Disable, + /// Make connection attempts to hosts in a random order. + Random, +} + /// A host specification. #[derive(Debug, Clone, PartialEq, Eq)] pub enum Host { @@ -129,6 +139,12 @@ pub enum Host { /// * `channel_binding` - Controls usage of channel binding in the authentication process. If set to `disable`, channel /// binding will not be used. If set to `prefer`, channel binding will be used if available, but not used otherwise. /// If set to `require`, the authentication process will fail if channel binding is not used. Defaults to `prefer`. +/// * `load_balance_hosts` - Controls the order in which the client tries to connect to the available hosts and +/// addresses. Once a connection attempt is successful no other hosts and addresses will be tried. This parameter +/// is typically used in combination with multiple host names or a DNS record that returns multiple IPs. If set to +/// `disable`, hosts and addresses will be tried in the order provided. If set to `random`, hosts will be tried +/// in a random order, and the IP addresses resolved from a hostname will also be tried in a random order. Defaults +/// to `disable`. /// /// ## Examples /// @@ -190,6 +206,7 @@ pub struct Config { pub(crate) keepalive_config: KeepaliveConfig, pub(crate) target_session_attrs: TargetSessionAttrs, pub(crate) channel_binding: ChannelBinding, + pub(crate) load_balance_hosts: LoadBalanceHosts, } impl Default for Config { @@ -222,6 +239,7 @@ impl Config { }, target_session_attrs: TargetSessionAttrs::Any, channel_binding: ChannelBinding::Prefer, + load_balance_hosts: LoadBalanceHosts::Disable, } } @@ -489,6 +507,19 @@ impl Config { self.channel_binding } + /// Sets the host load balancing behavior. + /// + /// Defaults to `disable`. + pub fn load_balance_hosts(&mut self, load_balance_hosts: LoadBalanceHosts) -> &mut Config { + self.load_balance_hosts = load_balance_hosts; + self + } + + /// Gets the host load balancing behavior. + pub fn get_load_balance_hosts(&self) -> LoadBalanceHosts { + self.load_balance_hosts + } + fn param(&mut self, key: &str, value: &str) -> Result<(), Error> { match key { "user" => { @@ -612,6 +643,18 @@ impl Config { }; self.channel_binding(channel_binding); } + "load_balance_hosts" => { + let load_balance_hosts = match value { + "disable" => LoadBalanceHosts::Disable, + "random" => LoadBalanceHosts::Random, + _ => { + return Err(Error::config_parse(Box::new(InvalidValue( + "load_balance_hosts", + )))) + } + }; + self.load_balance_hosts(load_balance_hosts); + } key => { return Err(Error::config_parse(Box::new(UnknownOption( key.to_string(), diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index 441ad1238..ca57b9cdd 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -1,12 +1,14 @@ -use crate::client::SocketConfig; -use crate::config::{Host, TargetSessionAttrs}; +use crate::client::{Addr, SocketConfig}; +use crate::config::{Host, LoadBalanceHosts, TargetSessionAttrs}; use crate::connect_raw::connect_raw; use crate::connect_socket::connect_socket; -use crate::tls::{MakeTlsConnect, TlsConnect}; +use crate::tls::MakeTlsConnect; use crate::{Client, Config, Connection, Error, SimpleQueryMessage, Socket}; use futures_util::{future, pin_mut, Future, FutureExt, Stream}; +use rand::seq::SliceRandom; use std::task::Poll; use std::{cmp, io}; +use tokio::net; pub async fn connect( mut tls: T, @@ -40,8 +42,13 @@ where return Err(Error::config("invalid number of ports".into())); } + let mut indices = (0..num_hosts).collect::>(); + if config.load_balance_hosts == LoadBalanceHosts::Random { + indices.shuffle(&mut rand::thread_rng()); + } + let mut error = None; - for i in 0..num_hosts { + for i in indices { let host = config.host.get(i); let hostaddr = config.hostaddr.get(i); let port = config @@ -59,25 +66,15 @@ where Some(Host::Unix(_)) => None, None => None, }; - let tls = tls - .make_tls_connect(hostname.as_deref().unwrap_or("")) - .map_err(|e| Error::tls(e.into()))?; // Try to use the value of hostaddr to establish the TCP connection, // fallback to host if hostaddr is not present. let addr = match hostaddr { Some(ipaddr) => Host::Tcp(ipaddr.to_string()), - None => { - if let Some(host) = host { - host.clone() - } else { - // This is unreachable. - return Err(Error::config("both host and hostaddr are empty".into())); - } - } + None => host.cloned().unwrap(), }; - match connect_once(addr, hostname, port, tls, config).await { + match connect_host(addr, hostname, port, &mut tls, config).await { Ok((client, connection)) => return Ok((client, connection)), Err(e) => error = Some(e), } @@ -86,18 +83,66 @@ where Err(error.unwrap()) } -async fn connect_once( +async fn connect_host( host: Host, hostname: Option, port: u16, - tls: T, + tls: &mut T, + config: &Config, +) -> Result<(Client, Connection), Error> +where + T: MakeTlsConnect, +{ + match host { + Host::Tcp(host) => { + let mut addrs = net::lookup_host((&*host, port)) + .await + .map_err(Error::connect)? + .collect::>(); + + if config.load_balance_hosts == LoadBalanceHosts::Random { + addrs.shuffle(&mut rand::thread_rng()); + } + + let mut last_err = None; + for addr in addrs { + match connect_once(Addr::Tcp(addr.ip()), hostname.as_deref(), port, tls, config) + .await + { + Ok(stream) => return Ok(stream), + Err(e) => { + last_err = Some(e); + continue; + } + }; + } + + Err(last_err.unwrap_or_else(|| { + Error::connect(io::Error::new( + io::ErrorKind::InvalidInput, + "could not resolve any addresses", + )) + })) + } + #[cfg(unix)] + Host::Unix(path) => { + connect_once(Addr::Unix(path), hostname.as_deref(), port, tls, config).await + } + } +} + +async fn connect_once( + addr: Addr, + hostname: Option<&str>, + port: u16, + tls: &mut T, config: &Config, ) -> Result<(Client, Connection), Error> where - T: TlsConnect, + T: MakeTlsConnect, { let socket = connect_socket( - &host, + &addr, port, config.connect_timeout, config.tcp_user_timeout, @@ -108,6 +153,10 @@ where }, ) .await?; + + let tls = tls + .make_tls_connect(hostname.unwrap_or("")) + .map_err(|e| Error::tls(e.into()))?; let has_hostname = hostname.is_some(); let (mut client, mut connection) = connect_raw(socket, tls, has_hostname, config).await?; @@ -152,8 +201,8 @@ where } client.set_socket_config(SocketConfig { - host, - hostname, + addr, + hostname: hostname.map(|s| s.to_string()), port, connect_timeout: config.connect_timeout, tcp_user_timeout: config.tcp_user_timeout, diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 1204ca1ff..082cad5dc 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -1,17 +1,17 @@ -use crate::config::Host; +use crate::client::Addr; use crate::keepalive::KeepaliveConfig; use crate::{Error, Socket}; use socket2::{SockRef, TcpKeepalive}; use std::future::Future; use std::io; use std::time::Duration; +use tokio::net::TcpStream; #[cfg(unix)] use tokio::net::UnixStream; -use tokio::net::{self, TcpStream}; use tokio::time; pub(crate) async fn connect_socket( - host: &Host, + addr: &Addr, port: u16, connect_timeout: Option, #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] tcp_user_timeout: Option< @@ -19,53 +19,32 @@ pub(crate) async fn connect_socket( >, keepalive_config: Option<&KeepaliveConfig>, ) -> Result { - match host { - Host::Tcp(host) => { - let addrs = net::lookup_host((&**host, port)) - .await - .map_err(Error::connect)?; + match addr { + Addr::Tcp(ip) => { + let stream = + connect_with_timeout(TcpStream::connect((*ip, port)), connect_timeout).await?; - let mut last_err = None; + stream.set_nodelay(true).map_err(Error::connect)?; - for addr in addrs { - let stream = - match connect_with_timeout(TcpStream::connect(addr), connect_timeout).await { - Ok(stream) => stream, - Err(e) => { - last_err = Some(e); - continue; - } - }; - - stream.set_nodelay(true).map_err(Error::connect)?; - - let sock_ref = SockRef::from(&stream); - #[cfg(target_os = "linux")] - { - sock_ref - .set_tcp_user_timeout(tcp_user_timeout) - .map_err(Error::connect)?; - } - - if let Some(keepalive_config) = keepalive_config { - sock_ref - .set_tcp_keepalive(&TcpKeepalive::from(keepalive_config)) - .map_err(Error::connect)?; - } + let sock_ref = SockRef::from(&stream); + #[cfg(target_os = "linux")] + { + sock_ref + .set_tcp_user_timeout(tcp_user_timeout) + .map_err(Error::connect)?; + } - return Ok(Socket::new_tcp(stream)); + if let Some(keepalive_config) = keepalive_config { + sock_ref + .set_tcp_keepalive(&TcpKeepalive::from(keepalive_config)) + .map_err(Error::connect)?; } - Err(last_err.unwrap_or_else(|| { - Error::connect(io::Error::new( - io::ErrorKind::InvalidInput, - "could not resolve any addresses", - )) - })) + return Ok(Socket::new_tcp(stream)); } #[cfg(unix)] - Host::Unix(path) => { - let path = path.join(format!(".s.PGSQL.{}", port)); + Addr::Unix(dir) => { + let path = dir.join(format!(".s.PGSQL.{}", port)); let socket = connect_with_timeout(UnixStream::connect(path), connect_timeout).await?; Ok(Socket::new_unix(socket)) } From babc8562276cb51288671530045faa094ee7f35d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 23 Jul 2023 09:55:27 -0400 Subject: [PATCH 294/420] clippy --- tokio-postgres/src/connect_socket.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/src/connect_socket.rs b/tokio-postgres/src/connect_socket.rs index 082cad5dc..f27131178 100644 --- a/tokio-postgres/src/connect_socket.rs +++ b/tokio-postgres/src/connect_socket.rs @@ -40,7 +40,7 @@ pub(crate) async fn connect_socket( .map_err(Error::connect)?; } - return Ok(Socket::new_tcp(stream)); + Ok(Socket::new_tcp(stream)) } #[cfg(unix)] Addr::Unix(dir) => { From 84aed6312fb01ffa7664290b86af5e442ed8f6e9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 23 Jul 2023 09:56:32 -0400 Subject: [PATCH 295/420] fix wasm build --- tokio-postgres/src/client.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 2185d2146..427a05049 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -25,7 +25,9 @@ use postgres_protocol::message::{backend::Message, frontend}; use postgres_types::BorrowToSql; use std::collections::HashMap; use std::fmt; +#[cfg(feature = "runtime")] use std::net::IpAddr; +#[cfg(feature = "runtime")] use std::path::PathBuf; use std::sync::Arc; use std::task::{Context, Poll}; From 98814b86bbe1c0daac2f29ffd55c675199b1877a Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Sat, 19 Aug 2023 16:22:18 +0300 Subject: [PATCH 296/420] Set user to executing processes' user by default. This mimics the behaviour of libpq and some other libraries (see #1024). This commit uses the `whoami` crate, and thus goes as far as defaulting the user to the executing process' user name on all operating systems. --- tokio-postgres/Cargo.toml | 1 + tokio-postgres/src/config.rs | 21 +++++++++++---------- tokio-postgres/src/connect_raw.rs | 9 ++------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 12c4bd689..29cf26829 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -59,6 +59,7 @@ postgres-types = { version = "0.2.4", path = "../postgres-types" } tokio = { version = "1.27", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } rand = "0.8.5" +whoami = "1.4.1" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] socket2 = { version = "0.5", features = ["all"] } diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 87d77d35a..a94667dc9 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -93,7 +93,7 @@ pub enum Host { /// /// ## Keys /// -/// * `user` - The username to authenticate with. Required. +/// * `user` - The username to authenticate with. Defaults to the user executing this process. /// * `password` - The password to authenticate with. /// * `dbname` - The name of the database to connect to. Defaults to the username. /// * `options` - Command line options used to configure the server. @@ -190,7 +190,7 @@ pub enum Host { /// ``` #[derive(Clone, PartialEq, Eq)] pub struct Config { - pub(crate) user: Option, + user: String, pub(crate) password: Option>, pub(crate) dbname: Option, pub(crate) options: Option, @@ -219,7 +219,7 @@ impl Config { /// Creates a new configuration. pub fn new() -> Config { Config { - user: None, + user: whoami::username(), password: None, dbname: None, options: None, @@ -245,16 +245,17 @@ impl Config { /// Sets the user to authenticate with. /// - /// Required. + /// If the user is not set, then this defaults to the user executing this process. pub fn user(&mut self, user: &str) -> &mut Config { - self.user = Some(user.to_string()); + self.user = user.to_string(); self } - /// Gets the user to authenticate with, if one has been configured with - /// the `user` method. - pub fn get_user(&self) -> Option<&str> { - self.user.as_deref() + /// Gets the user to authenticate with. + /// If no user has been configured with the [`user`](Config::user) method, + /// then this defaults to the user executing this process. + pub fn get_user(&self) -> &str { + &self.user } /// Sets the password to authenticate with. @@ -1124,7 +1125,7 @@ mod tests { fn test_simple_parsing() { let s = "user=pass_user dbname=postgres host=host1,host2 hostaddr=127.0.0.1,127.0.0.2 port=26257"; let config = s.parse::().unwrap(); - assert_eq!(Some("pass_user"), config.get_user()); + assert_eq!("pass_user", config.get_user()); assert_eq!(Some("postgres"), config.get_dbname()); assert_eq!( [ diff --git a/tokio-postgres/src/connect_raw.rs b/tokio-postgres/src/connect_raw.rs index 254ca9f0c..bb511c47e 100644 --- a/tokio-postgres/src/connect_raw.rs +++ b/tokio-postgres/src/connect_raw.rs @@ -113,9 +113,7 @@ where T: AsyncRead + AsyncWrite + Unpin, { let mut params = vec![("client_encoding", "UTF8")]; - if let Some(user) = &config.user { - params.push(("user", &**user)); - } + params.push(("user", config.get_user())); if let Some(dbname) = &config.dbname { params.push(("database", &**dbname)); } @@ -158,10 +156,7 @@ where Some(Message::AuthenticationMd5Password(body)) => { can_skip_channel_binding(config)?; - let user = config - .user - .as_ref() - .ok_or_else(|| Error::config("user missing".into()))?; + let user = config.get_user(); let pass = config .password .as_ref() From 4c4059a63d273b94badf1c90998ffaa7c67091c0 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Sat, 19 Aug 2023 18:48:57 +0300 Subject: [PATCH 297/420] Propagate changes from `tokio-postgres` to `postgres`. --- postgres/src/config.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index 2a8e63862..0e1fbde62 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -29,7 +29,7 @@ use tokio_postgres::{Error, Socket}; /// /// ## Keys /// -/// * `user` - The username to authenticate with. Required. +/// * `user` - The username to authenticate with. Defaults to the user executing this process. /// * `password` - The password to authenticate with. /// * `dbname` - The name of the database to connect to. Defaults to the username. /// * `options` - Command line options used to configure the server. @@ -143,15 +143,16 @@ impl Config { /// Sets the user to authenticate with. /// - /// Required. + /// If the user is not set, then this defaults to the user executing this process. pub fn user(&mut self, user: &str) -> &mut Config { self.config.user(user); self } - /// Gets the user to authenticate with, if one has been configured with - /// the `user` method. - pub fn get_user(&self) -> Option<&str> { + /// Gets the user to authenticate with. + /// If no user has been configured with the [`user`](Config::user) method, + /// then this defaults to the user executing this process. + pub fn get_user(&self) -> &str { self.config.get_user() } From 7a5b19a7861d784a0a743f89447d4c732ac44b90 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Sat, 19 Aug 2023 19:09:00 +0300 Subject: [PATCH 298/420] Update Rust version in CI to 1.67.0. --- .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 ebe0f600f..9a669a40f 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.65.0 + version: 1.67.0 - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - uses: actions/cache@v3 From a4543783707cc2fdbba3db4bfe1fc6168582de7e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 Aug 2023 19:53:26 -0400 Subject: [PATCH 299/420] Restore back compat --- postgres/src/config.rs | 7 +++++-- tokio-postgres/src/config.rs | 15 +++++++++------ tokio-postgres/src/connect_raw.rs | 4 ++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index 0e1fbde62..1839c9cb3 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -150,9 +150,12 @@ impl Config { } /// Gets the user to authenticate with. + /// /// If no user has been configured with the [`user`](Config::user) method, - /// then this defaults to the user executing this process. - pub fn get_user(&self) -> &str { + /// then this defaults to the user executing this process. It always + /// returns `Some`. + // FIXME remove option + pub fn get_user(&self) -> Option<&str> { self.config.get_user() } diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index a94667dc9..0da5fc689 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -190,7 +190,7 @@ pub enum Host { /// ``` #[derive(Clone, PartialEq, Eq)] pub struct Config { - user: String, + pub(crate) user: String, pub(crate) password: Option>, pub(crate) dbname: Option, pub(crate) options: Option, @@ -245,17 +245,20 @@ impl Config { /// Sets the user to authenticate with. /// - /// If the user is not set, then this defaults to the user executing this process. + /// Defaults to the user executing this process. pub fn user(&mut self, user: &str) -> &mut Config { self.user = user.to_string(); self } /// Gets the user to authenticate with. + /// /// If no user has been configured with the [`user`](Config::user) method, - /// then this defaults to the user executing this process. - pub fn get_user(&self) -> &str { - &self.user + /// then this defaults to the user executing this process. It always + /// returns `Some`. + // FIXME remove option + pub fn get_user(&self) -> Option<&str> { + Some(&self.user) } /// Sets the password to authenticate with. @@ -1125,7 +1128,7 @@ mod tests { fn test_simple_parsing() { let s = "user=pass_user dbname=postgres host=host1,host2 hostaddr=127.0.0.1,127.0.0.2 port=26257"; let config = s.parse::().unwrap(); - assert_eq!("pass_user", config.get_user()); + assert_eq!(Some("pass_user"), config.get_user()); assert_eq!(Some("postgres"), config.get_dbname()); assert_eq!( [ diff --git a/tokio-postgres/src/connect_raw.rs b/tokio-postgres/src/connect_raw.rs index bb511c47e..11cc48ef8 100644 --- a/tokio-postgres/src/connect_raw.rs +++ b/tokio-postgres/src/connect_raw.rs @@ -113,7 +113,7 @@ where T: AsyncRead + AsyncWrite + Unpin, { let mut params = vec![("client_encoding", "UTF8")]; - params.push(("user", config.get_user())); + params.push(("user", &config.user)); if let Some(dbname) = &config.dbname { params.push(("database", &**dbname)); } @@ -156,7 +156,7 @@ where Some(Message::AuthenticationMd5Password(body)) => { can_skip_channel_binding(config)?; - let user = config.get_user(); + let user = &config.user; let pass = config .password .as_ref() From 496f46c8f5e8e76e0b148c7ef57dbccc11778597 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 Aug 2023 20:04:18 -0400 Subject: [PATCH 300/420] Release postgres-protocol v0.6.6 --- postgres-protocol/CHANGELOG.md | 6 ++++++ postgres-protocol/Cargo.toml | 2 +- postgres-protocol/src/lib.rs | 1 - postgres-types/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/postgres-protocol/CHANGELOG.md b/postgres-protocol/CHANGELOG.md index 034fd637c..1c371675c 100644 --- a/postgres-protocol/CHANGELOG.md +++ b/postgres-protocol/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.6.6 -2023-08-19 + +### Added + +* Added the `js` feature for WASM support. + ## v0.6.5 - 2023-03-27 ### Added diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index ad609f6fa..b44994811 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-protocol" -version = "0.6.5" +version = "0.6.6" authors = ["Steven Fackler "] edition = "2018" description = "Low level Postgres protocol APIs" diff --git a/postgres-protocol/src/lib.rs b/postgres-protocol/src/lib.rs index 8b6ff508d..83d9bf55c 100644 --- a/postgres-protocol/src/lib.rs +++ b/postgres-protocol/src/lib.rs @@ -9,7 +9,6 @@ //! //! This library assumes that the `client_encoding` backend parameter has been //! set to `UTF8`. It will most likely not behave properly if that is not the case. -#![doc(html_root_url = "https://docs.rs/postgres-protocol/0.6")] #![warn(missing_docs, rust_2018_idioms, clippy::all)] use byteorder::{BigEndian, ByteOrder}; diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 35cdd6e7b..686d0036d 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -30,7 +30,7 @@ with-time-0_3 = ["time-03"] [dependencies] bytes = "1.0" fallible-iterator = "0.2" -postgres-protocol = { version = "0.6.4", path = "../postgres-protocol" } +postgres-protocol = { version = "0.6.5", path = "../postgres-protocol" } postgres-derive = { version = "0.4.2", optional = true, path = "../postgres-derive" } array-init = { version = "2", optional = true } diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 29cf26829..f9f49da3e 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -54,7 +54,7 @@ parking_lot = "0.12" percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.11" -postgres-protocol = { version = "0.6.5", path = "../postgres-protocol" } +postgres-protocol = { version = "0.6.6", path = "../postgres-protocol" } postgres-types = { version = "0.2.4", path = "../postgres-types" } tokio = { version = "1.27", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } From 43e15690f492f3ae8088677fd8d5df18f73b3e85 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 Aug 2023 20:11:35 -0400 Subject: [PATCH 301/420] Release postgres-derive v0.4.5 --- postgres-derive/CHANGELOG.md | 7 +++++++ postgres-derive/Cargo.toml | 2 +- postgres-types/Cargo.toml | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/postgres-derive/CHANGELOG.md b/postgres-derive/CHANGELOG.md index 22714acc2..b0075fa8e 100644 --- a/postgres-derive/CHANGELOG.md +++ b/postgres-derive/CHANGELOG.md @@ -1,5 +1,12 @@ # Change Log +## v0.4.5 - 2023-08-19 + +### Added + +* Added a `rename_all` option for enum and struct derives. +* Added an `allow_mismatch` option to disable strict enum variant checks against the Postgres type. + ## v0.4.4 - 2023-03-27 ### Changed diff --git a/postgres-derive/Cargo.toml b/postgres-derive/Cargo.toml index 78bec3d41..51ebb5663 100644 --- a/postgres-derive/Cargo.toml +++ b/postgres-derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-derive" -version = "0.4.4" +version = "0.4.5" authors = ["Steven Fackler "] license = "MIT/Apache-2.0" edition = "2018" diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 686d0036d..15de00702 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -31,7 +31,7 @@ with-time-0_3 = ["time-03"] bytes = "1.0" fallible-iterator = "0.2" postgres-protocol = { version = "0.6.5", path = "../postgres-protocol" } -postgres-derive = { version = "0.4.2", optional = true, path = "../postgres-derive" } +postgres-derive = { version = "0.4.5", optional = true, path = "../postgres-derive" } array-init = { version = "2", optional = true } bit-vec-06 = { version = "0.6", package = "bit-vec", optional = true } From 6f7ab44d5bc8548a4e7fb69d46d3b85a14101144 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 Aug 2023 20:14:01 -0400 Subject: [PATCH 302/420] Release postgres-types v0.2.6 --- postgres-types/CHANGELOG.md | 15 +++++++++++++-- postgres-types/Cargo.toml | 2 +- postgres-types/src/lib.rs | 1 - 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index 0f42f3495..72a1cbb6a 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -1,14 +1,25 @@ # Change Log +## v0.2.6 - 2023-08-19 + +### Fixed + +* Fixed serialization to `OIDVECTOR` and `INT2VECTOR`. + +### Added + +* Removed the `'static` requirement for the `impl BorrowToSql for Box`. +* Added a `ToSql` implementation for `Cow<[u8]>`. + ## v0.2.5 - 2023-03-27 -## Added +### Added * Added support for multi-range types. ## v0.2.4 - 2022-08-20 -## Added +### Added * Added `ToSql` and `FromSql` implementations for `Box<[T]>`. * Added `ToSql` and `FromSql` implementations for `[u8; N]` via the `array-impls` feature. diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 15de00702..193d159a1 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-types" -version = "0.2.5" +version = "0.2.6" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index d27adfe0e..52b5c773a 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -174,7 +174,6 @@ //! Meh, //! } //! ``` -#![doc(html_root_url = "https://docs.rs/postgres-types/0.2")] #![warn(clippy::all, rust_2018_idioms, missing_docs)] use fallible_iterator::FallibleIterator; use postgres_protocol::types::{self, ArrayDimension}; From 3d0a593ea610fb51b25a34087131470c94e3fe58 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 Aug 2023 20:20:13 -0400 Subject: [PATCH 303/420] Release tokio-postgres v0.7.9 --- tokio-postgres/CHANGELOG.md | 13 +++++++++++++ tokio-postgres/Cargo.toml | 4 ++-- tokio-postgres/src/lib.rs | 1 - 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 3345a1d43..41a1a65d1 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## v0.7.9 + +## Fixed + +* Fixed builds on OpenBSD. + +## Added + +* Added the `js` feature for WASM support. +* Added support for the `hostaddr` config option to bypass DNS lookups. +* Added support for the `load_balance_hosts` config option to randomize connection ordering. +* The `user` config option now defaults to the executing process's user. + ## v0.7.8 ## Added diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index f9f49da3e..3b33cc8f6 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.7.8" +version = "0.7.9" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -55,7 +55,7 @@ percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.11" postgres-protocol = { version = "0.6.6", path = "../postgres-protocol" } -postgres-types = { version = "0.2.4", path = "../postgres-types" } +postgres-types = { version = "0.2.5", path = "../postgres-types" } tokio = { version = "1.27", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } rand = "0.8.5" diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 2bb410187..ff8e93ddc 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -116,7 +116,6 @@ //! | `with-uuid-1` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 1.0 | no | //! | `with-time-0_2` | Enable support for the 0.2 version of the `time` crate. | [time](https://crates.io/crates/time/0.2.0) 0.2 | no | //! | `with-time-0_3` | Enable support for the 0.3 version of the `time` crate. | [time](https://crates.io/crates/time/0.3.0) 0.3 | no | -#![doc(html_root_url = "https://docs.rs/tokio-postgres/0.7")] #![warn(rust_2018_idioms, clippy::all, missing_docs)] pub use crate::cancel_token::CancelToken; From e08a38f9f6f06a67d699209d54097fa8a567a578 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 Aug 2023 20:33:21 -0400 Subject: [PATCH 304/420] sync postgres config up with tokio-postgres --- postgres/src/config.rs | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index 1839c9cb3..0f936fdc4 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -13,7 +13,9 @@ use std::sync::Arc; use std::time::Duration; use tokio::runtime; #[doc(inline)] -pub use tokio_postgres::config::{ChannelBinding, Host, SslMode, TargetSessionAttrs}; +pub use tokio_postgres::config::{ + ChannelBinding, Host, LoadBalanceHosts, SslMode, TargetSessionAttrs, +}; use tokio_postgres::error::DbError; use tokio_postgres::tls::{MakeTlsConnect, TlsConnect}; use tokio_postgres::{Error, Socket}; @@ -43,9 +45,9 @@ use tokio_postgres::{Error, Socket}; /// * `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, -/// - or if host specifies an IP address, that value will be used directly. +/// or if host specifies an IP address, that value will be used directly. /// Using `hostaddr` allows the application to avoid a host name look-up, which might be important in applications -/// with time constraints. However, a host name is required for verify-full SSL certificate verification. +/// with time constraints. However, a host name is required for TLS certificate verification. /// Specifically: /// * If `hostaddr` is specified without `host`, the value for `hostaddr` gives the server network address. /// The connection attempt will fail if the authentication method requires a host name; @@ -72,6 +74,15 @@ use tokio_postgres::{Error, Socket}; /// * `target_session_attrs` - Specifies requirements of the session. If set to `read-write`, the client will check that /// the `transaction_read_write` session parameter is set to `on`. This can be used to connect to the primary server /// in a database cluster as opposed to the secondary read-only mirrors. Defaults to `all`. +/// * `channel_binding` - Controls usage of channel binding in the authentication process. If set to `disable`, channel +/// binding will not be used. If set to `prefer`, channel binding will be used if available, but not used otherwise. +/// If set to `require`, the authentication process will fail if channel binding is not used. Defaults to `prefer`. +/// * `load_balance_hosts` - Controls the order in which the client tries to connect to the available hosts and +/// addresses. Once a connection attempt is successful no other hosts and addresses will be tried. This parameter +/// is typically used in combination with multiple host names or a DNS record that returns multiple IPs. If set to +/// `disable`, hosts and addresses will be tried in the order provided. If set to `random`, hosts will be tried +/// in a random order, and the IP addresses resolved from a hostname will also be tried in a random order. Defaults +/// to `disable`. /// /// ## Examples /// @@ -80,7 +91,7 @@ use tokio_postgres::{Error, Socket}; /// ``` /// /// ```not_rust -/// host=/var/run/postgresql,localhost port=1234 user=postgres password='password with spaces' +/// host=/var/lib/postgresql,localhost port=1234 user=postgres password='password with spaces' /// ``` /// /// ```not_rust @@ -94,7 +105,7 @@ use tokio_postgres::{Error, Socket}; /// # Url /// /// This format resembles a URL with a scheme of either `postgres://` or `postgresql://`. All components are optional, -/// and the format accept query parameters for all of the key-value pairs described in the section above. Multiple +/// and the format accepts query parameters for all of the key-value pairs described in the section above. Multiple /// host/port pairs can be comma-separated. Unix socket paths in the host section of the URL should be percent-encoded, /// as the path component of the URL specifies the database name. /// @@ -105,7 +116,7 @@ use tokio_postgres::{Error, Socket}; /// ``` /// /// ```not_rust -/// postgresql://user:password@%2Fvar%2Frun%2Fpostgresql/mydb?connect_timeout=10 +/// postgresql://user:password@%2Fvar%2Flib%2Fpostgresql/mydb?connect_timeout=10 /// ``` /// /// ```not_rust @@ -113,7 +124,7 @@ use tokio_postgres::{Error, Socket}; /// ``` /// /// ```not_rust -/// postgresql:///mydb?user=user&host=/var/run/postgresql +/// postgresql:///mydb?user=user&host=/var/lib/postgresql /// ``` #[derive(Clone)] pub struct Config { @@ -396,6 +407,19 @@ impl Config { self.config.get_channel_binding() } + /// Sets the host load balancing behavior. + /// + /// Defaults to `disable`. + pub fn load_balance_hosts(&mut self, load_balance_hosts: LoadBalanceHosts) -> &mut Config { + self.config.load_balance_hosts(load_balance_hosts); + self + } + + /// Gets the host load balancing behavior. + pub fn get_load_balance_hosts(&self) -> LoadBalanceHosts { + self.config.get_load_balance_hosts() + } + /// Sets the notice callback. /// /// This callback will be invoked with the contents of every From f45527fe5f4f566328973097511a33d771d3f300 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 Aug 2023 20:34:02 -0400 Subject: [PATCH 305/420] remove bogus docs --- postgres/src/config.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index 0f936fdc4..f83244b2e 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -1,6 +1,4 @@ //! Connection configuration. -//! -//! Requires the `runtime` Cargo feature (enabled by default). use crate::connection::Connection; use crate::Client; From 75cc986d8c40024eca45139edc6c366231d147ea Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 Aug 2023 20:37:16 -0400 Subject: [PATCH 306/420] Release postgres v0.19.6 --- postgres/CHANGELOG.md | 14 +++++++++++--- postgres/Cargo.toml | 8 +++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index b8263a04a..fe9e8dbe8 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,20 +1,28 @@ # Change Log +## v0.19.6 - 2023-08-19 + +### Added + +* Added support for the `hostaddr` config option to bypass DNS lookups. +* Added support for the `load_balance_hosts` config option to randomize connection ordering. +* The `user` config option now defaults to the executing process's user. + ## v0.19.5 - 2023-03-27 -## Added +### Added * Added `keepalives_interval` and `keepalives_retries` config options. * Added the `tcp_user_timeout` config option. * Added `RowIter::rows_affected`. -## Changed +### Changed * Passing an incorrect number of parameters to a query method now returns an error instead of panicking. ## v0.19.4 - 2022-08-21 -## Added +### Added * Added `ToSql` and `FromSql` implementations for `[u8; N]` via the `array-impls` feature. * Added support for `smol_str` 0.1 via the `with-smol_str-01` feature. diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 044bb91e1..ff626f86c 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.19.5" +version = "0.19.6" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -39,11 +39,9 @@ with-time-0_3 = ["tokio-postgres/with-time-0_3"] bytes = "1.0" fallible-iterator = "0.2" futures-util = { version = "0.3.14", features = ["sink"] } -tokio-postgres = { version = "0.7.8", path = "../tokio-postgres" } - -tokio = { version = "1.0", features = ["rt", "time"] } log = "0.4" +tokio-postgres = { version = "0.7.9", path = "../tokio-postgres" } +tokio = { version = "1.0", features = ["rt", "time"] } [dev-dependencies] criterion = "0.5" -tokio = { version = "1.0", features = ["rt-multi-thread"] } From cb609be758f3fb5af537f04b584a2ee0cebd5e79 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 25 Aug 2023 13:31:22 -0400 Subject: [PATCH 307/420] Defer username default --- postgres/src/config.rs | 8 ++------ tokio-postgres/src/config.rs | 16 ++++++---------- tokio-postgres/src/connect_raw.rs | 21 +++++++++++++++------ 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/postgres/src/config.rs b/postgres/src/config.rs index f83244b2e..a32ddc78e 100644 --- a/postgres/src/config.rs +++ b/postgres/src/config.rs @@ -158,12 +158,8 @@ impl Config { self } - /// Gets the user to authenticate with. - /// - /// If no user has been configured with the [`user`](Config::user) method, - /// then this defaults to the user executing this process. It always - /// returns `Some`. - // FIXME remove option + /// Gets the user to authenticate with, if one has been configured with + /// the `user` method. pub fn get_user(&self) -> Option<&str> { self.config.get_user() } diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index 0da5fc689..b178eac80 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -190,7 +190,7 @@ pub enum Host { /// ``` #[derive(Clone, PartialEq, Eq)] pub struct Config { - pub(crate) user: String, + pub(crate) user: Option, pub(crate) password: Option>, pub(crate) dbname: Option, pub(crate) options: Option, @@ -219,7 +219,7 @@ impl Config { /// Creates a new configuration. pub fn new() -> Config { Config { - user: whoami::username(), + user: None, password: None, dbname: None, options: None, @@ -247,18 +247,14 @@ impl Config { /// /// Defaults to the user executing this process. pub fn user(&mut self, user: &str) -> &mut Config { - self.user = user.to_string(); + self.user = Some(user.to_string()); self } - /// Gets the user to authenticate with. - /// - /// If no user has been configured with the [`user`](Config::user) method, - /// then this defaults to the user executing this process. It always - /// returns `Some`. - // FIXME remove option + /// Gets the user to authenticate with, if one has been configured with + /// the `user` method. pub fn get_user(&self) -> Option<&str> { - Some(&self.user) + self.user.as_deref() } /// Sets the password to authenticate with. diff --git a/tokio-postgres/src/connect_raw.rs b/tokio-postgres/src/connect_raw.rs index 11cc48ef8..f19bb50c4 100644 --- a/tokio-postgres/src/connect_raw.rs +++ b/tokio-postgres/src/connect_raw.rs @@ -96,8 +96,10 @@ where delayed: VecDeque::new(), }; - startup(&mut stream, config).await?; - authenticate(&mut stream, config).await?; + let user = config.user.clone().unwrap_or_else(whoami::username); + + startup(&mut stream, config, &user).await?; + authenticate(&mut stream, config, &user).await?; let (process_id, secret_key, parameters) = read_info(&mut stream).await?; let (sender, receiver) = mpsc::unbounded(); @@ -107,13 +109,17 @@ where Ok((client, connection)) } -async fn startup(stream: &mut StartupStream, config: &Config) -> Result<(), Error> +async fn startup( + stream: &mut StartupStream, + config: &Config, + user: &str, +) -> Result<(), Error> where S: AsyncRead + AsyncWrite + Unpin, T: AsyncRead + AsyncWrite + Unpin, { let mut params = vec![("client_encoding", "UTF8")]; - params.push(("user", &config.user)); + params.push(("user", user)); if let Some(dbname) = &config.dbname { params.push(("database", &**dbname)); } @@ -133,7 +139,11 @@ where .map_err(Error::io) } -async fn authenticate(stream: &mut StartupStream, config: &Config) -> Result<(), Error> +async fn authenticate( + stream: &mut StartupStream, + config: &Config, + user: &str, +) -> Result<(), Error> where S: AsyncRead + AsyncWrite + Unpin, T: TlsStream + Unpin, @@ -156,7 +166,6 @@ where Some(Message::AuthenticationMd5Password(body)) => { can_skip_channel_binding(config)?; - let user = &config.user; let pass = config .password .as_ref() From b411e5c3cb71d43fc9249b5d3ca38a7213470069 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 25 Aug 2023 13:35:48 -0400 Subject: [PATCH 308/420] clippy --- postgres-protocol/src/types/test.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/postgres-protocol/src/types/test.rs b/postgres-protocol/src/types/test.rs index 6f1851fc2..3e33b08f0 100644 --- a/postgres-protocol/src/types/test.rs +++ b/postgres-protocol/src/types/test.rs @@ -174,7 +174,7 @@ fn ltree_str() { let mut query = vec![1u8]; query.extend_from_slice("A.B.C".as_bytes()); - assert!(matches!(ltree_from_sql(query.as_slice()), Ok(_))) + assert!(ltree_from_sql(query.as_slice()).is_ok()) } #[test] @@ -182,7 +182,7 @@ fn ltree_wrong_version() { let mut query = vec![2u8]; query.extend_from_slice("A.B.C".as_bytes()); - assert!(matches!(ltree_from_sql(query.as_slice()), Err(_))) + assert!(ltree_from_sql(query.as_slice()).is_err()) } #[test] @@ -202,7 +202,7 @@ fn lquery_str() { let mut query = vec![1u8]; query.extend_from_slice("A.B.C".as_bytes()); - assert!(matches!(lquery_from_sql(query.as_slice()), Ok(_))) + assert!(lquery_from_sql(query.as_slice()).is_ok()) } #[test] @@ -210,7 +210,7 @@ fn lquery_wrong_version() { let mut query = vec![2u8]; query.extend_from_slice("A.B.C".as_bytes()); - assert!(matches!(lquery_from_sql(query.as_slice()), Err(_))) + assert!(lquery_from_sql(query.as_slice()).is_err()) } #[test] @@ -230,7 +230,7 @@ fn ltxtquery_str() { let mut query = vec![1u8]; query.extend_from_slice("a & b*".as_bytes()); - assert!(matches!(ltree_from_sql(query.as_slice()), Ok(_))) + assert!(ltree_from_sql(query.as_slice()).is_ok()) } #[test] @@ -238,5 +238,5 @@ fn ltxtquery_wrong_version() { let mut query = vec![2u8]; query.extend_from_slice("a & b*".as_bytes()); - assert!(matches!(ltree_from_sql(query.as_slice()), Err(_))) + assert!(ltree_from_sql(query.as_slice()).is_err()) } From 016e9a3b8557c267f650090e1501d5efd00de908 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 25 Aug 2023 13:40:01 -0400 Subject: [PATCH 309/420] avoid a silly clone --- tokio-postgres/src/connect_raw.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tokio-postgres/src/connect_raw.rs b/tokio-postgres/src/connect_raw.rs index f19bb50c4..19be9eb01 100644 --- a/tokio-postgres/src/connect_raw.rs +++ b/tokio-postgres/src/connect_raw.rs @@ -13,6 +13,7 @@ use postgres_protocol::authentication::sasl; use postgres_protocol::authentication::sasl::ScramSha256; use postgres_protocol::message::backend::{AuthenticationSaslBody, Message}; use postgres_protocol::message::frontend; +use std::borrow::Cow; use std::collections::{HashMap, VecDeque}; use std::io; use std::pin::Pin; @@ -96,7 +97,10 @@ where delayed: VecDeque::new(), }; - let user = config.user.clone().unwrap_or_else(whoami::username); + let user = config + .user + .as_deref() + .map_or_else(|| Cow::Owned(whoami::username()), Cow::Borrowed); startup(&mut stream, config, &user).await?; authenticate(&mut stream, config, &user).await?; From 234e20bb000ccf17d08341bd66e48d1105c3960a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 25 Aug 2023 13:40:40 -0400 Subject: [PATCH 310/420] bump ci version --- .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 9a669a40f..008158fb0 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.67.0 + version: 1.70.0 - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - uses: actions/cache@v3 From c50fcbd9fb6f0df53d2300fb429af1c6c128007f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 25 Aug 2023 13:45:34 -0400 Subject: [PATCH 311/420] Release tokio-postgres v0.7.10 --- tokio-postgres/CHANGELOG.md | 6 ++++++ tokio-postgres/Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 41a1a65d1..2bee9a1c4 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.7.10 + +## Fixed + +* Defered default username lookup to avoid regressing `Config` behavior. + ## v0.7.9 ## Fixed diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 3b33cc8f6..ec5e3cbec 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.7.9" +version = "0.7.10" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" From c5ff8cfd86e897b7c197f52684a37a4f17cecb75 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 25 Aug 2023 13:48:08 -0400 Subject: [PATCH 312/420] Release postgres v0.19.7 --- postgres/CHANGELOG.md | 6 ++++++ postgres/Cargo.toml | 4 ++-- tokio-postgres/CHANGELOG.md | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index fe9e8dbe8..7f856b5ac 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.19.7 - 2023-08-25 + +## Fixed + +* Defered default username lookup to avoid regressing `Config` behavior. + ## v0.19.6 - 2023-08-19 ### Added diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index ff626f86c..18406da9f 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.19.6" +version = "0.19.7" authors = ["Steven Fackler "] edition = "2018" license = "MIT/Apache-2.0" @@ -40,7 +40,7 @@ bytes = "1.0" fallible-iterator = "0.2" futures-util = { version = "0.3.14", features = ["sink"] } log = "0.4" -tokio-postgres = { version = "0.7.9", path = "../tokio-postgres" } +tokio-postgres = { version = "0.7.10", 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 2bee9a1c4..75448d130 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,12 +1,12 @@ # Change Log -## v0.7.10 +## v0.7.10 - 2023-08-25 ## Fixed * Defered default username lookup to avoid regressing `Config` behavior. -## v0.7.9 +## v0.7.9 - 2023-08-19 ## Fixed @@ -19,7 +19,7 @@ * Added support for the `load_balance_hosts` config option to randomize connection ordering. * The `user` config option now defaults to the executing process's user. -## v0.7.8 +## v0.7.8 - 2023-05-27 ## Added From b1306a4a74317ac142ae9b93445360e9597380ec Mon Sep 17 00:00:00 2001 From: ds-cbo <82801887+ds-cbo@users.noreply.github.com> Date: Fri, 20 Oct 2023 16:31:41 +0200 Subject: [PATCH 313/420] remove rustc-serialize dependency --- postgres-types/Cargo.toml | 4 +++- postgres/src/lib.rs | 2 +- tokio-postgres/CHANGELOG.md | 6 ++++++ tokio-postgres/Cargo.toml | 3 +-- tokio-postgres/src/lib.rs | 2 +- tokio-postgres/tests/test/types/eui48_04.rs | 18 ------------------ tokio-postgres/tests/test/types/mod.rs | 2 -- 7 files changed, 12 insertions(+), 25 deletions(-) delete mode 100644 tokio-postgres/tests/test/types/eui48_04.rs diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 193d159a1..cfd083637 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -39,8 +39,10 @@ chrono-04 = { version = "0.4.16", package = "chrono", default-features = false, "clock", ], optional = true } cidr-02 = { version = "0.2", 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 } -eui48-1 = { version = "1.0", package = "eui48", optional = true } +eui48-1 = { version = "1.0", package = "eui48", optional = true, default-features = false } geo-types-06 = { version = "0.6", package = "geo-types", optional = true } geo-types-0_7 = { version = "0.7", package = "geo-types", optional = true } serde-1 = { version = "1.0", package = "serde", optional = true } diff --git a/postgres/src/lib.rs b/postgres/src/lib.rs index fbe85cbde..ddf1609ad 100644 --- a/postgres/src/lib.rs +++ b/postgres/src/lib.rs @@ -55,7 +55,7 @@ //! | ------- | ----------- | ------------------ | ------- | //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | -//! | `with-eui48-0_4` | Enable support for the 0.4 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | +//! | `with-eui48-0_4` | Enable support for the 0.4 version of the `eui48` crate. This is deprecated and will be removed. | [eui48](https://crates.io/crates/eui48) 0.4 | no | //! | `with-eui48-1` | Enable support for the 1.0 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 1.0 | no | //! | `with-geo-types-0_6` | Enable support for the 0.6 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.6.0) 0.6 | no | //! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 75448d130..bd076eef9 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## Unreleased + +* Disable `rustc-serialize` compatibility of `eui48-1` dependency +* Remove tests for `eui48-04` + + ## v0.7.10 - 2023-08-25 ## Fixed diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index ec5e3cbec..bb58eb2d9 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -78,8 +78,7 @@ tokio = { version = "1.0", features = [ bit-vec-06 = { version = "0.6", package = "bit-vec" } chrono-04 = { version = "0.4", package = "chrono", default-features = false } -eui48-04 = { version = "0.4", package = "eui48" } -eui48-1 = { version = "1.0", package = "eui48" } +eui48-1 = { version = "1.0", package = "eui48", default-features = false } geo-types-06 = { version = "0.6", package = "geo-types" } geo-types-07 = { version = "0.7", package = "geo-types" } serde-1 = { version = "1.0", package = "serde" } diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index ff8e93ddc..2973d33b0 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -107,7 +107,7 @@ //! | `array-impls` | Enables `ToSql` and `FromSql` trait impls for arrays | - | no | //! | `with-bit-vec-0_6` | Enable support for the `bit-vec` crate. | [bit-vec](https://crates.io/crates/bit-vec) 0.6 | no | //! | `with-chrono-0_4` | Enable support for the `chrono` crate. | [chrono](https://crates.io/crates/chrono) 0.4 | no | -//! | `with-eui48-0_4` | Enable support for the 0.4 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 0.4 | no | +//! | `with-eui48-0_4` | Enable support for the 0.4 version of the `eui48` crate. This is deprecated and will be removed. | [eui48](https://crates.io/crates/eui48) 0.4 | no | //! | `with-eui48-1` | Enable support for the 1.0 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 1.0 | no | //! | `with-geo-types-0_6` | Enable support for the 0.6 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.6.0) 0.6 | no | //! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | diff --git a/tokio-postgres/tests/test/types/eui48_04.rs b/tokio-postgres/tests/test/types/eui48_04.rs deleted file mode 100644 index 074faa37e..000000000 --- a/tokio-postgres/tests/test/types/eui48_04.rs +++ /dev/null @@ -1,18 +0,0 @@ -use eui48_04::MacAddress; - -use crate::types::test_type; - -#[tokio::test] -async fn test_eui48_params() { - test_type( - "MACADDR", - &[ - ( - Some(MacAddress::parse_str("12-34-56-AB-CD-EF").unwrap()), - "'12-34-56-ab-cd-ef'", - ), - (None, "NULL"), - ], - ) - .await -} diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index f1a44da08..62d54372a 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -17,8 +17,6 @@ use bytes::BytesMut; mod bit_vec_06; #[cfg(feature = "with-chrono-0_4")] mod chrono_04; -#[cfg(feature = "with-eui48-0_4")] -mod eui48_04; #[cfg(feature = "with-eui48-1")] mod eui48_1; #[cfg(feature = "with-geo-types-0_6")] From ea9e0e5cddc2e772179027e635afa11d64feea2b Mon Sep 17 00:00:00 2001 From: ds-cbo <82801887+ds-cbo@users.noreply.github.com> Date: Mon, 30 Oct 2023 10:43:56 +0100 Subject: [PATCH 314/420] replace deprecated chrono::DateTime::from_utc --- postgres-types/src/chrono_04.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres-types/src/chrono_04.rs b/postgres-types/src/chrono_04.rs index 0ec92437d..6011b549e 100644 --- a/postgres-types/src/chrono_04.rs +++ b/postgres-types/src/chrono_04.rs @@ -40,7 +40,7 @@ impl ToSql for NaiveDateTime { impl<'a> FromSql<'a> for DateTime { fn from_sql(type_: &Type, raw: &[u8]) -> Result, Box> { let naive = NaiveDateTime::from_sql(type_, raw)?; - Ok(DateTime::from_utc(naive, Utc)) + Ok(Utc::from_utc_datetime(naive)) } accepts!(TIMESTAMPTZ); From b4ebc4e7ec6ee52930bc22e2ad29b66687852623 Mon Sep 17 00:00:00 2001 From: ds-cbo <82801887+ds-cbo@users.noreply.github.com> Date: Mon, 30 Oct 2023 16:39:50 +0100 Subject: [PATCH 315/420] add missing import --- postgres-types/src/chrono_04.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/postgres-types/src/chrono_04.rs b/postgres-types/src/chrono_04.rs index 6011b549e..f995d483c 100644 --- a/postgres-types/src/chrono_04.rs +++ b/postgres-types/src/chrono_04.rs @@ -1,5 +1,7 @@ use bytes::BytesMut; -use chrono_04::{DateTime, Duration, FixedOffset, Local, NaiveDate, NaiveDateTime, NaiveTime, Utc}; +use chrono_04::{ + DateTime, Duration, FixedOffset, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc, +}; use postgres_protocol::types; use std::error::Error; From 19a6ef767bf6b2070ffe9efd43af514b6a31f2d2 Mon Sep 17 00:00:00 2001 From: ds-cbo <82801887+ds-cbo@users.noreply.github.com> Date: Tue, 31 Oct 2023 09:54:13 +0100 Subject: [PATCH 316/420] fix more deprecated chrono functions --- postgres-types/src/chrono_04.rs | 2 +- tokio-postgres/tests/test/types/chrono_04.rs | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/postgres-types/src/chrono_04.rs b/postgres-types/src/chrono_04.rs index f995d483c..d599bde02 100644 --- a/postgres-types/src/chrono_04.rs +++ b/postgres-types/src/chrono_04.rs @@ -42,7 +42,7 @@ impl ToSql for NaiveDateTime { impl<'a> FromSql<'a> for DateTime { fn from_sql(type_: &Type, raw: &[u8]) -> Result, Box> { let naive = NaiveDateTime::from_sql(type_, raw)?; - Ok(Utc::from_utc_datetime(naive)) + Ok(Utc.from_utc_datetime(&naive)) } accepts!(TIMESTAMPTZ); diff --git a/tokio-postgres/tests/test/types/chrono_04.rs b/tokio-postgres/tests/test/types/chrono_04.rs index a8e9e5afa..b010055ba 100644 --- a/tokio-postgres/tests/test/types/chrono_04.rs +++ b/tokio-postgres/tests/test/types/chrono_04.rs @@ -53,10 +53,9 @@ async fn test_with_special_naive_date_time_params() { async fn test_date_time_params() { fn make_check(time: &str) -> (Option>, &str) { ( - Some( - Utc.datetime_from_str(time, "'%Y-%m-%d %H:%M:%S.%f'") - .unwrap(), - ), + Some(Utc.from_utc_datetime( + &NaiveDateTime::parse_from_str(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap(), + )), time, ) } @@ -76,10 +75,9 @@ async fn test_date_time_params() { async fn test_with_special_date_time_params() { fn make_check(time: &str) -> (Timestamp>, &str) { ( - Timestamp::Value( - Utc.datetime_from_str(time, "'%Y-%m-%d %H:%M:%S.%f'") - .unwrap(), - ), + Timestamp::Value(Utc.from_utc_datetime( + &NaiveDateTime::parse_from_str(time, "'%Y-%m-%d %H:%M:%S.%f'").unwrap(), + )), time, ) } From 863c1d6039e8fe114e48d62c0451d6eb5e4867a2 Mon Sep 17 00:00:00 2001 From: James Guthrie Date: Tue, 7 Nov 2023 22:09:39 +0100 Subject: [PATCH 317/420] fix code block --- postgres-types/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 52b5c773a..aaf145e6b 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -168,6 +168,8 @@ //! 'Happy' //! ); //! ``` +//! +//! ```rust //! #[postgres(allow_mismatch)] //! enum Mood { //! Happy, From 10edbcb46c44933417e8d2e7a1c1d63c4119beb3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 7 Nov 2023 16:23:06 -0500 Subject: [PATCH 318/420] Update lib.rs --- postgres-types/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index aaf145e6b..2f02f6e5f 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -170,6 +170,11 @@ //! ``` //! //! ```rust +//! # #[cfg(feature = "derive")] +//! use postgres_types::{ToSql, FromSql}; +//! +//! # #[cfg(feature = "derive")] +//! #[derive(Debug, ToSql, FromSql)] //! #[postgres(allow_mismatch)] //! enum Mood { //! Happy, From 02bab67280f8a850b816754b29eb0364708604ec Mon Sep 17 00:00:00 2001 From: "Michael P. Jung" Date: Tue, 5 Dec 2023 13:54:20 +0100 Subject: [PATCH 319/420] Add table_oid and field_id to columns of prepared statements --- tokio-postgres/CHANGELOG.md | 2 +- tokio-postgres/src/prepare.rs | 8 +++++++- tokio-postgres/src/statement.rs | 23 +++++++++++++++++------ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index bd076eef9..9f5eb9521 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -4,7 +4,7 @@ * Disable `rustc-serialize` compatibility of `eui48-1` dependency * Remove tests for `eui48-04` - +* Add `table_oid` and `field_id` fields to `Columns` struct of prepared statements. ## v0.7.10 - 2023-08-25 diff --git a/tokio-postgres/src/prepare.rs b/tokio-postgres/src/prepare.rs index e3f09a7c2..1ab34e2df 100644 --- a/tokio-postgres/src/prepare.rs +++ b/tokio-postgres/src/prepare.rs @@ -12,6 +12,7 @@ use log::debug; use postgres_protocol::message::backend::Message; use postgres_protocol::message::frontend; use std::future::Future; +use std::num::{NonZeroI16, NonZeroU32}; use std::pin::Pin; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -95,7 +96,12 @@ pub async fn prepare( let mut it = row_description.fields(); while let Some(field) = it.next().map_err(Error::parse)? { let type_ = get_type(client, field.type_oid()).await?; - let column = Column::new(field.name().to_string(), type_); + let column = Column { + name: field.name().to_string(), + table_oid: NonZeroU32::new(field.table_oid()), + column_id: NonZeroI16::new(field.column_id()), + type_, + }; columns.push(column); } } diff --git a/tokio-postgres/src/statement.rs b/tokio-postgres/src/statement.rs index 97561a8e4..73d56c220 100644 --- a/tokio-postgres/src/statement.rs +++ b/tokio-postgres/src/statement.rs @@ -5,6 +5,7 @@ use crate::types::Type; use postgres_protocol::message::frontend; use std::{ fmt, + num::{NonZeroI16, NonZeroU32}, sync::{Arc, Weak}, }; @@ -66,20 +67,28 @@ impl Statement { /// Information about a column of a query. pub struct Column { - name: String, - type_: Type, + pub(crate) name: String, + pub(crate) table_oid: Option, + pub(crate) column_id: Option, + pub(crate) type_: Type, } impl Column { - pub(crate) fn new(name: String, type_: Type) -> Column { - Column { name, type_ } - } - /// Returns the name of the column. pub fn name(&self) -> &str { &self.name } + /// Returns the OID of the underlying database table. + pub fn table_oid(&self) -> Option { + self.table_oid + } + + /// Return the column ID within the underlying database table. + pub fn column_id(&self) -> Option { + self.column_id + } + /// Returns the type of the column. pub fn type_(&self) -> &Type { &self.type_ @@ -90,6 +99,8 @@ impl fmt::Debug for Column { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("Column") .field("name", &self.name) + .field("table_oid", &self.table_oid) + .field("column_id", &self.column_id) .field("type", &self.type_) .finish() } From 87876150d79e637767247176e339bf01a8b32d3b Mon Sep 17 00:00:00 2001 From: "Michael P. Jung" Date: Tue, 5 Dec 2023 14:09:44 +0100 Subject: [PATCH 320/420] Simplify Debug impl of Column --- tokio-postgres/src/prepare.rs | 2 +- tokio-postgres/src/statement.rs | 17 +++-------------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/tokio-postgres/src/prepare.rs b/tokio-postgres/src/prepare.rs index 1ab34e2df..0302cdb4c 100644 --- a/tokio-postgres/src/prepare.rs +++ b/tokio-postgres/src/prepare.rs @@ -100,7 +100,7 @@ pub async fn prepare( name: field.name().to_string(), table_oid: NonZeroU32::new(field.table_oid()), column_id: NonZeroI16::new(field.column_id()), - type_, + r#type: type_, }; columns.push(column); } diff --git a/tokio-postgres/src/statement.rs b/tokio-postgres/src/statement.rs index 73d56c220..fe3b6b7a1 100644 --- a/tokio-postgres/src/statement.rs +++ b/tokio-postgres/src/statement.rs @@ -4,7 +4,6 @@ use crate::connection::RequestMessages; use crate::types::Type; use postgres_protocol::message::frontend; use std::{ - fmt, num::{NonZeroI16, NonZeroU32}, sync::{Arc, Weak}, }; @@ -66,11 +65,12 @@ impl Statement { } /// Information about a column of a query. +#[derive(Debug)] pub struct Column { pub(crate) name: String, pub(crate) table_oid: Option, pub(crate) column_id: Option, - pub(crate) type_: Type, + pub(crate) r#type: Type, } impl Column { @@ -91,17 +91,6 @@ impl Column { /// Returns the type of the column. pub fn type_(&self) -> &Type { - &self.type_ - } -} - -impl fmt::Debug for Column { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("Column") - .field("name", &self.name) - .field("table_oid", &self.table_oid) - .field("column_id", &self.column_id) - .field("type", &self.type_) - .finish() + &self.r#type } } From bbc04145de7a83dfa66cb3cf4a68878da2c1cc32 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 11 Dec 2023 19:06:22 -0500 Subject: [PATCH 321/420] Update id types --- tokio-postgres/src/prepare.rs | 5 ++--- tokio-postgres/src/statement.rs | 13 +++++-------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/tokio-postgres/src/prepare.rs b/tokio-postgres/src/prepare.rs index 0302cdb4c..07fb45694 100644 --- a/tokio-postgres/src/prepare.rs +++ b/tokio-postgres/src/prepare.rs @@ -12,7 +12,6 @@ use log::debug; use postgres_protocol::message::backend::Message; use postgres_protocol::message::frontend; use std::future::Future; -use std::num::{NonZeroI16, NonZeroU32}; use std::pin::Pin; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -98,8 +97,8 @@ pub async fn prepare( let type_ = get_type(client, field.type_oid()).await?; let column = Column { name: field.name().to_string(), - table_oid: NonZeroU32::new(field.table_oid()), - column_id: NonZeroI16::new(field.column_id()), + table_oid: Some(field.table_oid()).filter(|n| *n != 0), + column_id: Some(field.column_id()).filter(|n| *n != 0), r#type: type_, }; columns.push(column); diff --git a/tokio-postgres/src/statement.rs b/tokio-postgres/src/statement.rs index fe3b6b7a1..c5d657738 100644 --- a/tokio-postgres/src/statement.rs +++ b/tokio-postgres/src/statement.rs @@ -3,10 +3,7 @@ use crate::codec::FrontendMessage; use crate::connection::RequestMessages; use crate::types::Type; use postgres_protocol::message::frontend; -use std::{ - num::{NonZeroI16, NonZeroU32}, - sync::{Arc, Weak}, -}; +use std::sync::{Arc, Weak}; struct StatementInner { client: Weak, @@ -68,8 +65,8 @@ impl Statement { #[derive(Debug)] pub struct Column { pub(crate) name: String, - pub(crate) table_oid: Option, - pub(crate) column_id: Option, + pub(crate) table_oid: Option, + pub(crate) column_id: Option, pub(crate) r#type: Type, } @@ -80,12 +77,12 @@ impl Column { } /// Returns the OID of the underlying database table. - pub fn table_oid(&self) -> Option { + pub fn table_oid(&self) -> Option { self.table_oid } /// Return the column ID within the underlying database table. - pub fn column_id(&self) -> Option { + pub fn column_id(&self) -> Option { self.column_id } From 90c92c2ae8577a8e771333c701280485c45ad602 Mon Sep 17 00:00:00 2001 From: Troy Benson Date: Mon, 15 Jan 2024 16:33:27 +0000 Subject: [PATCH 322/420] feat(types): add default derive to json wrapper Adds a Default impl for `Json where T: Default` allowing for other structs to use the wrapper and implement Default. --- postgres-types/src/serde_json_1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres-types/src/serde_json_1.rs b/postgres-types/src/serde_json_1.rs index b98d561d1..715c33f98 100644 --- a/postgres-types/src/serde_json_1.rs +++ b/postgres-types/src/serde_json_1.rs @@ -7,7 +7,7 @@ use std::fmt::Debug; use std::io::Read; /// A wrapper type to allow arbitrary `Serialize`/`Deserialize` types to convert to Postgres JSON values. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Default, Debug, PartialEq, Eq)] pub struct Json(pub T); impl<'a, T> FromSql<'a> for Json From 2f150a7e50ee03cbccf52792b7e4507dbcef0301 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 13:49:51 +0000 Subject: [PATCH 323/420] Update env_logger requirement from 0.10 to 0.11 Updates the requirements on [env_logger](https://github.com/rust-cli/env_logger) to permit the latest version. - [Release notes](https://github.com/rust-cli/env_logger/releases) - [Changelog](https://github.com/rust-cli/env_logger/blob/main/CHANGELOG.md) - [Commits](https://github.com/rust-cli/env_logger/compare/v0.10.0...v0.11.0) --- updated-dependencies: - dependency-name: env_logger dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- tokio-postgres/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index bb58eb2d9..237f3d2f1 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -67,7 +67,7 @@ socket2 = { version = "0.5", features = ["all"] } [dev-dependencies] futures-executor = "0.3" criterion = "0.5" -env_logger = "0.10" +env_logger = "0.11" tokio = { version = "1.0", features = [ "macros", "net", From 7bc3deb989b3030681b742801bfeaca7f67e1e1e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 22 Jan 2024 20:49:47 -0500 Subject: [PATCH 324/420] Update ci.yml --- .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 008158fb0..0cc823d35 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.70.0 + version: 1.71.0 - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - uses: actions/cache@v3 From a92c6eb2b65e12d7145a14cec23888d64c4b13e4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 22 Jan 2024 20:54:11 -0500 Subject: [PATCH 325/420] Update main.rs --- tokio-postgres/tests/test/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index 0ab4a7bab..737f46631 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -303,6 +303,7 @@ async fn custom_range() { } #[tokio::test] +#[allow(clippy::get_first)] async fn simple_query() { let client = connect("user=postgres").await; From 289cf887600785e723628dcbc1f7a2267cd52917 Mon Sep 17 00:00:00 2001 From: Charles Samuels Date: Fri, 16 Feb 2024 10:55:08 -0800 Subject: [PATCH 326/420] add #[track_caller] to the Row::get() functions This small quality-of-life improvement changes these errors: thread '' panicked at /../.cargo/registry/src/index.crates.io-6f17d22bba15001f/tokio-postgres-0.7.10/src/row.rs:151:25: error retrieving column 0: error deserializing column 0: a Postgres value was `NULL` to: thread '' panicked at my-program.rs:100:25: error retrieving column 0: error deserializing column 0: a Postgres value was `NULL` --- tokio-postgres/src/row.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tokio-postgres/src/row.rs b/tokio-postgres/src/row.rs index db179b432..3c79de603 100644 --- a/tokio-postgres/src/row.rs +++ b/tokio-postgres/src/row.rs @@ -141,6 +141,7 @@ impl Row { /// # Panics /// /// Panics if the index is out of bounds or if the value cannot be converted to the specified type. + #[track_caller] pub fn get<'a, I, T>(&'a self, idx: I) -> T where I: RowIndex + fmt::Display, @@ -239,6 +240,7 @@ impl SimpleQueryRow { /// # Panics /// /// Panics if the index is out of bounds or if the value cannot be converted to the specified type. + #[track_caller] pub fn get(&self, idx: I) -> Option<&str> where I: RowIndex + fmt::Display, From 25314a91c95dc8f75062e337eb363188c63df5d4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 17 Feb 2024 09:52:44 -0500 Subject: [PATCH 327/420] Bump CI version --- .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 0cc823d35..641a42722 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.71.0 + version: 1.74.0 - run: echo "version=$(rustc --version)" >> $GITHUB_OUTPUT id: rust-version - uses: actions/cache@v3 From a9ca481c88fb619c6d35f2a6b64253bb46240c5d Mon Sep 17 00:00:00 2001 From: "chandr-andr (Kiselev Aleksandr)" Date: Sun, 3 Mar 2024 16:37:30 +0100 Subject: [PATCH 328/420] Added ReadOnly session attr --- tokio-postgres/src/config.rs | 3 +++ tokio-postgres/tests/test/parse.rs | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index b178eac80..c78346fff 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -34,6 +34,8 @@ pub enum TargetSessionAttrs { Any, /// The session must allow writes. ReadWrite, + /// The session allow only reads. + ReadOnly, } /// TLS configuration. @@ -622,6 +624,7 @@ impl Config { let target_session_attrs = match value { "any" => TargetSessionAttrs::Any, "read-write" => TargetSessionAttrs::ReadWrite, + "read-only" => TargetSessionAttrs::ReadOnly, _ => { return Err(Error::config_parse(Box::new(InvalidValue( "target_session_attrs", diff --git a/tokio-postgres/tests/test/parse.rs b/tokio-postgres/tests/test/parse.rs index 2c11899ca..04d422e27 100644 --- a/tokio-postgres/tests/test/parse.rs +++ b/tokio-postgres/tests/test/parse.rs @@ -34,6 +34,14 @@ fn settings() { .keepalives_idle(Duration::from_secs(30)) .target_session_attrs(TargetSessionAttrs::ReadWrite), ); + check( + "connect_timeout=3 keepalives=0 keepalives_idle=30 target_session_attrs=read-only", + Config::new() + .connect_timeout(Duration::from_secs(3)) + .keepalives(false) + .keepalives_idle(Duration::from_secs(30)) + .target_session_attrs(TargetSessionAttrs::ReadOnly), + ); } #[test] From 6a01730cbfed5d9c0aa694401704e6fe7ec0c8b5 Mon Sep 17 00:00:00 2001 From: "chandr-andr (Kiselev Aleksandr)" Date: Sun, 3 Mar 2024 19:17:50 +0100 Subject: [PATCH 329/420] Added ReadOnly session attr --- tokio-postgres/src/connect.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/src/connect.rs b/tokio-postgres/src/connect.rs index ca57b9cdd..8189cb91c 100644 --- a/tokio-postgres/src/connect.rs +++ b/tokio-postgres/src/connect.rs @@ -160,7 +160,7 @@ where let has_hostname = hostname.is_some(); let (mut client, mut connection) = connect_raw(socket, tls, has_hostname, config).await?; - if let TargetSessionAttrs::ReadWrite = config.target_session_attrs { + if config.target_session_attrs != TargetSessionAttrs::Any { let rows = client.simple_query_raw("SHOW transaction_read_only"); pin_mut!(rows); @@ -185,11 +185,21 @@ where match next.await.transpose()? { Some(SimpleQueryMessage::Row(row)) => { - if row.try_get(0)? == Some("on") { + let read_only_result = row.try_get(0)?; + if read_only_result == Some("on") + && config.target_session_attrs == TargetSessionAttrs::ReadWrite + { return Err(Error::connect(io::Error::new( io::ErrorKind::PermissionDenied, "database does not allow writes", ))); + } else if read_only_result == Some("off") + && config.target_session_attrs == TargetSessionAttrs::ReadOnly + { + return Err(Error::connect(io::Error::new( + io::ErrorKind::PermissionDenied, + "database is not read only", + ))); } else { break; } From 4217553586c4ce390179a281834b8f2c3197863e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 13:45:26 +0000 Subject: [PATCH 330/420] Update base64 requirement from 0.21 to 0.22 Updates the requirements on [base64](https://github.com/marshallpierce/rust-base64) to permit the latest version. - [Changelog](https://github.com/marshallpierce/rust-base64/blob/master/RELEASE-NOTES.md) - [Commits](https://github.com/marshallpierce/rust-base64/compare/v0.21.0...v0.22.0) --- updated-dependencies: - dependency-name: base64 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- 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 b44994811..bc83fc4e6 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -13,7 +13,7 @@ default = [] js = ["getrandom/js"] [dependencies] -base64 = "0.21" +base64 = "0.22" byteorder = "1.0" bytes = "1.0" fallible-iterator = "0.2" From 9d7c43c73955638624e75957a333fac5d9be1c02 Mon Sep 17 00:00:00 2001 From: novacrazy Date: Sun, 11 Feb 2024 03:03:19 -0600 Subject: [PATCH 331/420] Shrink query_opt/query_one codegen size very slightly --- tokio-postgres/src/client.rs | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 427a05049..d48a23a60 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -274,19 +274,9 @@ impl Client { where T: ?Sized + ToStatement, { - let stream = self.query_raw(statement, slice_iter(params)).await?; - pin_mut!(stream); - - let row = match stream.try_next().await? { - Some(row) => row, - None => return Err(Error::row_count()), - }; - - if stream.try_next().await?.is_some() { - return Err(Error::row_count()); - } - - Ok(row) + self.query_opt(statement, params) + .await + .and_then(|res| res.ok_or_else(Error::row_count)) } /// Executes a statements which returns zero or one rows, returning it. @@ -310,16 +300,22 @@ impl Client { let stream = self.query_raw(statement, slice_iter(params)).await?; pin_mut!(stream); - let row = match stream.try_next().await? { - Some(row) => row, - None => return Ok(None), - }; + let mut first = None; + + // Originally this was two calls to `try_next().await?`, + // once for the first element, and second to error if more than one. + // + // However, this new form with only one .await in a loop generates + // slightly smaller codegen/stack usage for the resulting future. + while let Some(row) = stream.try_next().await? { + if first.is_some() { + return Err(Error::row_count()); + } - if stream.try_next().await?.is_some() { - return Err(Error::row_count()); + first = Some(row); } - Ok(Some(row)) + Ok(first) } /// The maximally flexible version of [`query`]. From 97436303232127dbd448d71a50c6365bdbee083c Mon Sep 17 00:00:00 2001 From: laxjesse Date: Wed, 13 Mar 2024 11:10:58 -0400 Subject: [PATCH 332/420] use `split_once` instead of `split` to parse lsn strings [`str::split`](https://doc.rust-lang.org/std/primitive.str.html#method.split) allocates a vector and generates considerably more instructions when compiled than [`str::split_once`](https://doc.rust-lang.org/std/primitive.str.html#method.split_once). [`u64::from_str_radix(split_lo, 16)`](https://doc.rust-lang.org/std/primitive.u64.html#method.from_str_radix) will error if the `lsn_str` contains more than one `/` so this change should result in the same behavior as the current implementation despite not explicitly checking this. --- postgres-types/CHANGELOG.md | 6 ++++++ postgres-types/src/pg_lsn.rs | 18 ++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index 72a1cbb6a..157a2cc7d 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## Unreleased + +### Changed + +* `FromStr` implementation for `PgLsn` no longer allocates a `Vec` when splitting an lsn string on it's `/`. + ## v0.2.6 - 2023-08-19 ### Fixed diff --git a/postgres-types/src/pg_lsn.rs b/postgres-types/src/pg_lsn.rs index f0bbf4022..f339f9689 100644 --- a/postgres-types/src/pg_lsn.rs +++ b/postgres-types/src/pg_lsn.rs @@ -33,16 +33,14 @@ impl FromStr for PgLsn { type Err = ParseLsnError; fn from_str(lsn_str: &str) -> Result { - let split: Vec<&str> = lsn_str.split('/').collect(); - if split.len() == 2 { - let (hi, lo) = ( - u64::from_str_radix(split[0], 16).map_err(|_| ParseLsnError(()))?, - u64::from_str_radix(split[1], 16).map_err(|_| ParseLsnError(()))?, - ); - Ok(PgLsn((hi << 32) | lo)) - } else { - Err(ParseLsnError(())) - } + let Some((split_hi, split_lo)) = lsn_str.split_once('/') else { + return Err(ParseLsnError(())); + }; + let (hi, lo) = ( + u64::from_str_radix(split_hi, 16).map_err(|_| ParseLsnError(()))?, + u64::from_str_radix(split_lo, 16).map_err(|_| ParseLsnError(()))?, + ); + Ok(PgLsn((hi << 32) | lo)) } } From 3836a3052065bccf53001b832a21823204bfa137 Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Wed, 10 Apr 2024 17:42:13 +0200 Subject: [PATCH 333/420] Make license metadata SPDX compliant --- postgres-derive/Cargo.toml | 4 ++-- postgres-native-tls/Cargo.toml | 2 +- postgres-openssl/Cargo.toml | 2 +- postgres-protocol/Cargo.toml | 2 +- postgres-types/Cargo.toml | 2 +- postgres/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/postgres-derive/Cargo.toml b/postgres-derive/Cargo.toml index 51ebb5663..5d1604b24 100644 --- a/postgres-derive/Cargo.toml +++ b/postgres-derive/Cargo.toml @@ -2,7 +2,7 @@ name = "postgres-derive" version = "0.4.5" authors = ["Steven Fackler "] -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" edition = "2018" description = "An internal crate used by postgres-types" repository = "https://github.com/sfackler/rust-postgres" @@ -15,4 +15,4 @@ test = false syn = "2.0" proc-macro2 = "1.0" quote = "1.0" -heck = "0.4" \ No newline at end of file +heck = "0.4" diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index 1f2f6385d..936eeeaa4 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -3,7 +3,7 @@ name = "postgres-native-tls" version = "0.5.0" authors = ["Steven Fackler "] edition = "2018" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" description = "TLS support for tokio-postgres via native-tls" repository = "https://github.com/sfackler/rust-postgres" readme = "../README.md" diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index 8671308af..b7ebd3385 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -3,7 +3,7 @@ name = "postgres-openssl" version = "0.5.0" authors = ["Steven Fackler "] edition = "2018" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" description = "TLS support for tokio-postgres via openssl" repository = "https://github.com/sfackler/rust-postgres" readme = "../README.md" diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index bc83fc4e6..a8a130495 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -4,7 +4,7 @@ version = "0.6.6" authors = ["Steven Fackler "] edition = "2018" description = "Low level Postgres protocol APIs" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" repository = "https://github.com/sfackler/rust-postgres" readme = "../README.md" diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index cfd083637..bf011251b 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -3,7 +3,7 @@ name = "postgres-types" version = "0.2.6" authors = ["Steven Fackler "] edition = "2018" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" description = "Conversions between Rust and Postgres values" repository = "https://github.com/sfackler/rust-postgres" readme = "../README.md" diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 18406da9f..2ff3c875e 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -3,7 +3,7 @@ name = "postgres" version = "0.19.7" authors = ["Steven Fackler "] edition = "2018" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" description = "A native, synchronous PostgreSQL client" repository = "https://github.com/sfackler/rust-postgres" readme = "../README.md" diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 237f3d2f1..b3e56314f 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -3,7 +3,7 @@ name = "tokio-postgres" version = "0.7.10" authors = ["Steven Fackler "] edition = "2018" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" description = "A native, asynchronous PostgreSQL client" repository = "https://github.com/sfackler/rust-postgres" readme = "../README.md" From 670cd7d5802dfb3b0b6b1eadd480f5c9730bb0b0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Apr 2024 16:21:21 +0000 Subject: [PATCH 334/420] Update heck requirement from 0.4 to 0.5 --- updated-dependencies: - dependency-name: heck dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- postgres-derive/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/postgres-derive/Cargo.toml b/postgres-derive/Cargo.toml index 5d1604b24..cbae6c77b 100644 --- a/postgres-derive/Cargo.toml +++ b/postgres-derive/Cargo.toml @@ -15,4 +15,4 @@ test = false syn = "2.0" proc-macro2 = "1.0" quote = "1.0" -heck = "0.4" +heck = "0.5" From 3c6dbe9b8c7bfad82c646f34092e3fa1d321b723 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Wed, 1 May 2024 22:46:06 -0400 Subject: [PATCH 335/420] Avoid extra clone in config if possible Using `impl Into` instead of `&str` in a fn arg allows both `&str` and `String` as parameters - thus if the caller already has a String object that it doesn't need, it can pass it in without extra cloning. The same might be done with the password, but may require closer look. --- tokio-postgres/src/config.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/tokio-postgres/src/config.rs b/tokio-postgres/src/config.rs index c78346fff..62b45f793 100644 --- a/tokio-postgres/src/config.rs +++ b/tokio-postgres/src/config.rs @@ -248,8 +248,8 @@ impl Config { /// Sets the user to authenticate with. /// /// Defaults to the user executing this process. - pub fn user(&mut self, user: &str) -> &mut Config { - self.user = Some(user.to_string()); + pub fn user(&mut self, user: impl Into) -> &mut Config { + self.user = Some(user.into()); self } @@ -277,8 +277,8 @@ impl Config { /// Sets the name of the database to connect to. /// /// Defaults to the user. - pub fn dbname(&mut self, dbname: &str) -> &mut Config { - self.dbname = Some(dbname.to_string()); + pub fn dbname(&mut self, dbname: impl Into) -> &mut Config { + self.dbname = Some(dbname.into()); self } @@ -289,8 +289,8 @@ impl Config { } /// Sets command line options used to configure the server. - pub fn options(&mut self, options: &str) -> &mut Config { - self.options = Some(options.to_string()); + pub fn options(&mut self, options: impl Into) -> &mut Config { + self.options = Some(options.into()); self } @@ -301,8 +301,8 @@ impl Config { } /// Sets the value of the `application_name` runtime parameter. - pub fn application_name(&mut self, application_name: &str) -> &mut Config { - self.application_name = Some(application_name.to_string()); + pub fn application_name(&mut self, application_name: impl Into) -> &mut Config { + self.application_name = Some(application_name.into()); self } @@ -330,7 +330,9 @@ impl Config { /// Multiple hosts can be specified by calling this method multiple times, and each will be tried in order. On Unix /// systems, a host starting with a `/` is interpreted as a path to a directory containing Unix domain sockets. /// There must be either no hosts, or the same number of hosts as hostaddrs. - pub fn host(&mut self, host: &str) -> &mut Config { + pub fn host(&mut self, host: impl Into) -> &mut Config { + let host = host.into(); + #[cfg(unix)] { if host.starts_with('/') { @@ -338,7 +340,7 @@ impl Config { } } - self.host.push(Host::Tcp(host.to_string())); + self.host.push(Host::Tcp(host)); self } @@ -990,7 +992,7 @@ impl<'a> UrlParser<'a> { let mut it = creds.splitn(2, ':'); let user = self.decode(it.next().unwrap())?; - self.config.user(&user); + self.config.user(user); if let Some(password) = it.next() { let password = Cow::from(percent_encoding::percent_decode(password.as_bytes())); @@ -1053,7 +1055,7 @@ impl<'a> UrlParser<'a> { }; if !dbname.is_empty() { - self.config.dbname(&self.decode(dbname)?); + self.config.dbname(self.decode(dbname)?); } Ok(()) From d5d75d3a2f064425436c08b6a8f2da2b985aab3d Mon Sep 17 00:00:00 2001 From: vsuryamurthy Date: Thu, 23 May 2024 17:18:41 +0200 Subject: [PATCH 336/420] add simple_query to GenericClient in tokio_postgres --- tokio-postgres/CHANGELOG.md | 1 + tokio-postgres/src/generic_client.rs | 35 ++++++++++++++++++---------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index 9f5eb9521..775c22e34 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -5,6 +5,7 @@ * Disable `rustc-serialize` compatibility of `eui48-1` dependency * Remove tests for `eui48-04` * Add `table_oid` and `field_id` fields to `Columns` struct of prepared statements. +* Add `GenericClient::simple_query`. ## v0.7.10 - 2023-08-25 diff --git a/tokio-postgres/src/generic_client.rs b/tokio-postgres/src/generic_client.rs index 50cff9712..d80dd3b86 100644 --- a/tokio-postgres/src/generic_client.rs +++ b/tokio-postgres/src/generic_client.rs @@ -1,6 +1,6 @@ use crate::query::RowStream; use crate::types::{BorrowToSql, ToSql, Type}; -use crate::{Client, Error, Row, Statement, ToStatement, Transaction}; +use crate::{Client, Error, Row, SimpleQueryMessage, Statement, ToStatement, Transaction}; use async_trait::async_trait; mod private { @@ -12,12 +12,12 @@ mod private { /// This trait is "sealed", and cannot be implemented outside of this crate. #[async_trait] pub trait GenericClient: private::Sealed { - /// Like `Client::execute`. + /// Like [`Client::execute`]. async fn execute(&self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result where T: ?Sized + ToStatement + Sync + Send; - /// Like `Client::execute_raw`. + /// Like [`Client::execute_raw`]. async fn execute_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement + Sync + Send, @@ -25,12 +25,12 @@ pub trait GenericClient: private::Sealed { I: IntoIterator + Sync + Send, I::IntoIter: ExactSizeIterator; - /// Like `Client::query`. + /// Like [`Client::query`]. async fn query(&self, query: &T, params: &[&(dyn ToSql + Sync)]) -> Result, Error> where T: ?Sized + ToStatement + Sync + Send; - /// Like `Client::query_one`. + /// Like [`Client::query_one`]. async fn query_one( &self, statement: &T, @@ -39,7 +39,7 @@ pub trait GenericClient: private::Sealed { where T: ?Sized + ToStatement + Sync + Send; - /// Like `Client::query_opt`. + /// Like [`Client::query_opt`]. async fn query_opt( &self, statement: &T, @@ -48,7 +48,7 @@ pub trait GenericClient: private::Sealed { where T: ?Sized + ToStatement + Sync + Send; - /// Like `Client::query_raw`. + /// Like [`Client::query_raw`]. async fn query_raw(&self, statement: &T, params: I) -> Result where T: ?Sized + ToStatement + Sync + Send, @@ -56,23 +56,26 @@ pub trait GenericClient: private::Sealed { I: IntoIterator + Sync + Send, I::IntoIter: ExactSizeIterator; - /// Like `Client::prepare`. + /// Like [`Client::prepare`]. async fn prepare(&self, query: &str) -> Result; - /// Like `Client::prepare_typed`. + /// Like [`Client::prepare_typed`]. async fn prepare_typed( &self, query: &str, parameter_types: &[Type], ) -> Result; - /// Like `Client::transaction`. + /// Like [`Client::transaction`]. async fn transaction(&mut self) -> Result, Error>; - /// Like `Client::batch_execute`. + /// Like [`Client::batch_execute`]. async fn batch_execute(&self, query: &str) -> Result<(), Error>; - /// Returns a reference to the underlying `Client`. + /// Like [`Client::simple_query`]. + async fn simple_query(&self, query: &str) -> Result, Error>; + + /// Returns a reference to the underlying [`Client`]. fn client(&self) -> &Client; } @@ -156,6 +159,10 @@ impl GenericClient for Client { self.batch_execute(query).await } + async fn simple_query(&self, query: &str) -> Result, Error> { + self.simple_query(query).await + } + fn client(&self) -> &Client { self } @@ -243,6 +250,10 @@ impl GenericClient for Transaction<'_> { self.batch_execute(query).await } + async fn simple_query(&self, query: &str) -> Result, Error> { + self.simple_query(query).await + } + fn client(&self) -> &Client { self.client() } From fbecae11ace79376b20ae8b9a587ab577e8287cd Mon Sep 17 00:00:00 2001 From: Duarte Nunes Date: Mon, 11 Mar 2024 14:43:50 -0300 Subject: [PATCH 337/420] feat(types): add 'js' feature for wasm Enables the "js" feature of postgres-protocol. --- postgres-types/Cargo.toml | 1 + tokio-postgres/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index bf011251b..33296db2c 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -13,6 +13,7 @@ categories = ["database"] [features] derive = ["postgres-derive"] array-impls = ["array-init"] +js = ["postgres-protocol/js"] with-bit-vec-0_6 = ["bit-vec-06"] with-cidr-0_2 = ["cidr-02"] with-chrono-0_4 = ["chrono-04"] diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index b3e56314f..2e080cfb2 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -40,7 +40,7 @@ with-uuid-0_8 = ["postgres-types/with-uuid-0_8"] with-uuid-1 = ["postgres-types/with-uuid-1"] with-time-0_2 = ["postgres-types/with-time-0_2"] with-time-0_3 = ["postgres-types/with-time-0_3"] -js = ["postgres-protocol/js"] +js = ["postgres-protocol/js", "postgres-types/js"] [dependencies] async-trait = "0.1" From 6cd4652bad6ac8474235c23d0e4e96cc4aa4d8db Mon Sep 17 00:00:00 2001 From: Dane Rigby Date: Tue, 28 May 2024 21:57:27 -0500 Subject: [PATCH 338/420] Add RowDescription to SimpleQueryMessage --- tokio-postgres/src/lib.rs | 6 ++++++ tokio-postgres/src/simple_query.rs | 5 +++-- tokio-postgres/tests/test/main.rs | 13 ++++++++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 2973d33b0..d650f4db9 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -118,6 +118,10 @@ //! | `with-time-0_3` | Enable support for the 0.3 version of the `time` crate. | [time](https://crates.io/crates/time/0.3.0) 0.3 | no | #![warn(rust_2018_idioms, clippy::all, missing_docs)] +use std::sync::Arc; + +use simple_query::SimpleColumn; + pub use crate::cancel_token::CancelToken; pub use crate::client::Client; pub use crate::config::Config; @@ -248,6 +252,8 @@ pub enum SimpleQueryMessage { /// /// The number of rows modified or selected is returned. CommandComplete(u64), + /// Column values of the proceeding row values + RowDescription(Arc<[SimpleColumn]>) } fn slice_iter<'a>( diff --git a/tokio-postgres/src/simple_query.rs b/tokio-postgres/src/simple_query.rs index bcc6d928b..4e0b7734d 100644 --- a/tokio-postgres/src/simple_query.rs +++ b/tokio-postgres/src/simple_query.rs @@ -95,14 +95,15 @@ impl Stream for SimpleQueryStream { return Poll::Ready(Some(Ok(SimpleQueryMessage::CommandComplete(0)))); } Message::RowDescription(body) => { - let columns = body + let columns: Arc<[SimpleColumn]> = body .fields() .map(|f| Ok(SimpleColumn::new(f.name().to_string()))) .collect::>() .map_err(Error::parse)? .into(); - *this.columns = Some(columns); + *this.columns = Some(columns.clone()); + return Poll::Ready(Some(Ok(SimpleQueryMessage::RowDescription(columns.clone())))); } Message::DataRow(body) => { let row = match &this.columns { diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index 737f46631..4fa72aec9 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -328,6 +328,13 @@ async fn simple_query() { _ => panic!("unexpected message"), } match &messages[2] { + SimpleQueryMessage::RowDescription(columns) => { + assert_eq!(columns.get(0).map(|c| c.name()), Some("id")); + assert_eq!(columns.get(1).map(|c| c.name()), Some("name")); + } + _ => panic!("unexpected message") + } + match &messages[3] { SimpleQueryMessage::Row(row) => { assert_eq!(row.columns().get(0).map(|c| c.name()), Some("id")); assert_eq!(row.columns().get(1).map(|c| c.name()), Some("name")); @@ -336,7 +343,7 @@ async fn simple_query() { } _ => panic!("unexpected message"), } - match &messages[3] { + match &messages[4] { SimpleQueryMessage::Row(row) => { assert_eq!(row.columns().get(0).map(|c| c.name()), Some("id")); assert_eq!(row.columns().get(1).map(|c| c.name()), Some("name")); @@ -345,11 +352,11 @@ async fn simple_query() { } _ => panic!("unexpected message"), } - match messages[4] { + match messages[5] { SimpleQueryMessage::CommandComplete(2) => {} _ => panic!("unexpected message"), } - assert_eq!(messages.len(), 5); + assert_eq!(messages.len(), 6); } #[tokio::test] From 7afead9a13d54f1c5ce9bef5eda1fb7ced26db61 Mon Sep 17 00:00:00 2001 From: Dane Rigby Date: Tue, 28 May 2024 22:08:41 -0500 Subject: [PATCH 339/420] Formatting updates --- tokio-postgres/src/lib.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index d650f4db9..6c6266736 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -118,10 +118,6 @@ //! | `with-time-0_3` | Enable support for the 0.3 version of the `time` crate. | [time](https://crates.io/crates/time/0.3.0) 0.3 | no | #![warn(rust_2018_idioms, clippy::all, missing_docs)] -use std::sync::Arc; - -use simple_query::SimpleColumn; - pub use crate::cancel_token::CancelToken; pub use crate::client::Client; pub use crate::config::Config; @@ -134,7 +130,7 @@ pub use crate::generic_client::GenericClient; pub use crate::portal::Portal; pub use crate::query::RowStream; pub use crate::row::{Row, SimpleQueryRow}; -pub use crate::simple_query::SimpleQueryStream; +pub use crate::simple_query::{SimpleQueryStream, SimpleColumn}; #[cfg(feature = "runtime")] pub use crate::socket::Socket; pub use crate::statement::{Column, Statement}; @@ -145,6 +141,7 @@ pub use crate::to_statement::ToStatement; pub use crate::transaction::Transaction; pub use crate::transaction_builder::{IsolationLevel, TransactionBuilder}; use crate::types::ToSql; +use std::sync::Arc; pub mod binary_copy; mod bind; From eec06021d9ebe1c1c2fcc47666a76ce257ae2891 Mon Sep 17 00:00:00 2001 From: Dane Rigby Date: Tue, 28 May 2024 23:50:50 -0500 Subject: [PATCH 340/420] Clippy compliance --- tokio-postgres/src/simple_query.rs | 54 ++++++++++++++---------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/tokio-postgres/src/simple_query.rs b/tokio-postgres/src/simple_query.rs index 4e0b7734d..e84806d36 100644 --- a/tokio-postgres/src/simple_query.rs +++ b/tokio-postgres/src/simple_query.rs @@ -85,36 +85,34 @@ impl Stream for SimpleQueryStream { fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let this = self.project(); - loop { - match ready!(this.responses.poll_next(cx)?) { - Message::CommandComplete(body) => { - let rows = extract_row_affected(&body)?; - return Poll::Ready(Some(Ok(SimpleQueryMessage::CommandComplete(rows)))); - } - Message::EmptyQueryResponse => { - return Poll::Ready(Some(Ok(SimpleQueryMessage::CommandComplete(0)))); - } - Message::RowDescription(body) => { - let columns: Arc<[SimpleColumn]> = body - .fields() - .map(|f| Ok(SimpleColumn::new(f.name().to_string()))) - .collect::>() - .map_err(Error::parse)? - .into(); + match ready!(this.responses.poll_next(cx)?) { + Message::CommandComplete(body) => { + let rows = extract_row_affected(&body)?; + Poll::Ready(Some(Ok(SimpleQueryMessage::CommandComplete(rows)))) + } + Message::EmptyQueryResponse => { + Poll::Ready(Some(Ok(SimpleQueryMessage::CommandComplete(0)))) + } + Message::RowDescription(body) => { + let columns: Arc<[SimpleColumn]> = body + .fields() + .map(|f| Ok(SimpleColumn::new(f.name().to_string()))) + .collect::>() + .map_err(Error::parse)? + .into(); - *this.columns = Some(columns.clone()); - return Poll::Ready(Some(Ok(SimpleQueryMessage::RowDescription(columns.clone())))); - } - Message::DataRow(body) => { - let row = match &this.columns { - Some(columns) => SimpleQueryRow::new(columns.clone(), body)?, - None => return Poll::Ready(Some(Err(Error::unexpected_message()))), - }; - return Poll::Ready(Some(Ok(SimpleQueryMessage::Row(row)))); - } - Message::ReadyForQuery(_) => return Poll::Ready(None), - _ => return Poll::Ready(Some(Err(Error::unexpected_message()))), + *this.columns = Some(columns.clone()); + Poll::Ready(Some(Ok(SimpleQueryMessage::RowDescription(columns.clone())))) + } + Message::DataRow(body) => { + let row = match &this.columns { + Some(columns) => SimpleQueryRow::new(columns.clone(), body)?, + None => return Poll::Ready(Some(Err(Error::unexpected_message()))), + }; + Poll::Ready(Some(Ok(SimpleQueryMessage::Row(row)))) } + Message::ReadyForQuery(_) => Poll::Ready(None), + _ => Poll::Ready(Some(Err(Error::unexpected_message()))), } } } From bd6350c2fff2201d680a1814acf7a9208f4b7ad4 Mon Sep 17 00:00:00 2001 From: Dane Rigby Date: Wed, 29 May 2024 23:32:18 -0500 Subject: [PATCH 341/420] Formatting --- tokio-postgres/src/lib.rs | 4 ++-- tokio-postgres/src/simple_query.rs | 4 +++- tokio-postgres/tests/test/main.rs | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index 6c6266736..a603158fb 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -130,7 +130,7 @@ pub use crate::generic_client::GenericClient; pub use crate::portal::Portal; pub use crate::query::RowStream; pub use crate::row::{Row, SimpleQueryRow}; -pub use crate::simple_query::{SimpleQueryStream, SimpleColumn}; +pub use crate::simple_query::{SimpleColumn, SimpleQueryStream}; #[cfg(feature = "runtime")] pub use crate::socket::Socket; pub use crate::statement::{Column, Statement}; @@ -250,7 +250,7 @@ pub enum SimpleQueryMessage { /// The number of rows modified or selected is returned. CommandComplete(u64), /// Column values of the proceeding row values - RowDescription(Arc<[SimpleColumn]>) + RowDescription(Arc<[SimpleColumn]>), } fn slice_iter<'a>( diff --git a/tokio-postgres/src/simple_query.rs b/tokio-postgres/src/simple_query.rs index e84806d36..86af8e739 100644 --- a/tokio-postgres/src/simple_query.rs +++ b/tokio-postgres/src/simple_query.rs @@ -102,7 +102,9 @@ impl Stream for SimpleQueryStream { .into(); *this.columns = Some(columns.clone()); - Poll::Ready(Some(Ok(SimpleQueryMessage::RowDescription(columns.clone())))) + Poll::Ready(Some(Ok(SimpleQueryMessage::RowDescription( + columns.clone(), + )))) } Message::DataRow(body) => { let row = match &this.columns { diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index 4fa72aec9..e85960ab6 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -330,9 +330,9 @@ async fn simple_query() { match &messages[2] { SimpleQueryMessage::RowDescription(columns) => { assert_eq!(columns.get(0).map(|c| c.name()), Some("id")); - assert_eq!(columns.get(1).map(|c| c.name()), Some("name")); + assert_eq!(columns.get(1).map(|c| c.name()), Some("name")); } - _ => panic!("unexpected message") + _ => panic!("unexpected message"), } match &messages[3] { SimpleQueryMessage::Row(row) => { From f3976680c6d7004b04b3ba39f90f2956ce6d7010 Mon Sep 17 00:00:00 2001 From: Ramnivas Laddad Date: Sun, 26 May 2024 11:05:00 -0700 Subject: [PATCH 342/420] Work with pools that don't support prepared statements Introduce a new `query_with_param_types` method that allows to specify Postgres type parameters. This obviated the need to use prepared statementsjust to obtain parameter types for a query. It then combines parse, bind, and execute in a single packet. Related: #1017, #1067 --- tokio-postgres/src/client.rs | 82 +++++++++++++++ tokio-postgres/src/generic_client.rs | 46 +++++++++ tokio-postgres/src/prepare.rs | 2 +- tokio-postgres/src/query.rs | 146 ++++++++++++++++++++++++++- tokio-postgres/src/statement.rs | 13 +++ tokio-postgres/src/transaction.rs | 27 +++++ tokio-postgres/tests/test/main.rs | 106 +++++++++++++++++++ 7 files changed, 416 insertions(+), 6 deletions(-) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index d48a23a60..431bfa792 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -364,6 +364,88 @@ impl Client { query::query(&self.inner, statement, params).await } + /// Like `query`, but requires the types of query parameters to be explicitly specified. + /// + /// Compared to `query`, this method allows performing queries without three round trips (for prepare, execute, and close). Thus, + /// this is suitable in environments where prepared statements aren't supported (such as Cloudflare Workers with Hyperdrive). + /// + /// # Examples + /// + /// ```no_run + /// # async fn async_main(client: &tokio_postgres::Client) -> Result<(), tokio_postgres::Error> { + /// use tokio_postgres::types::ToSql; + /// use tokio_postgres::types::Type; + /// use futures_util::{pin_mut, TryStreamExt}; + /// + /// let rows = client.query_with_param_types( + /// "SELECT foo FROM bar WHERE biz = $1 AND baz = $2", + /// &[(&"first param", Type::TEXT), (&2i32, Type::INT4)], + /// ).await?; + /// + /// for row in rows { + /// let foo: i32 = row.get("foo"); + /// println!("foo: {}", foo); + /// } + /// # Ok(()) + /// # } + /// ``` + pub async fn query_with_param_types( + &self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result, Error> { + self.query_raw_with_param_types(statement, params) + .await? + .try_collect() + .await + } + + /// The maximally flexible version of [`query_with_param_types`]. + /// + /// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list + /// provided, 1-indexed. + /// + /// The parameters must specify value along with their Postgres type. This allows performing + /// queries without three round trips (for prepare, execute, and close). + /// + /// [`query_with_param_types`]: #method.query_with_param_types + /// + /// # Examples + /// + /// ```no_run + /// # async fn async_main(client: &tokio_postgres::Client) -> Result<(), tokio_postgres::Error> { + /// use tokio_postgres::types::ToSql; + /// use tokio_postgres::types::Type; + /// use futures_util::{pin_mut, TryStreamExt}; + /// + /// let mut it = client.query_raw_with_param_types( + /// "SELECT foo FROM bar WHERE biz = $1 AND baz = $2", + /// &[(&"first param", Type::TEXT), (&2i32, Type::INT4)], + /// ).await?; + /// + /// pin_mut!(it); + /// while let Some(row) = it.try_next().await? { + /// let foo: i32 = row.get("foo"); + /// println!("foo: {}", foo); + /// } + /// # Ok(()) + /// # } + /// ``` + pub async fn query_raw_with_param_types( + &self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result { + fn slice_iter<'a>( + s: &'a [(&'a (dyn ToSql + Sync), Type)], + ) -> impl ExactSizeIterator + 'a { + s.iter() + .map(|(param, param_type)| (*param as _, param_type.clone())) + } + + query::query_with_param_types(&self.inner, statement, slice_iter(params)).await + } + /// Executes a statement, returning the number of rows modified. /// /// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list diff --git a/tokio-postgres/src/generic_client.rs b/tokio-postgres/src/generic_client.rs index 50cff9712..3a0b09233 100644 --- a/tokio-postgres/src/generic_client.rs +++ b/tokio-postgres/src/generic_client.rs @@ -56,6 +56,20 @@ pub trait GenericClient: private::Sealed { I: IntoIterator + Sync + Send, I::IntoIter: ExactSizeIterator; + /// Like `Client::query_with_param_types` + async fn query_with_param_types( + &self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result, Error>; + + /// Like `Client::query_raw_with_param_types`. + async fn query_raw_with_param_types( + &self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result; + /// Like `Client::prepare`. async fn prepare(&self, query: &str) -> Result; @@ -136,6 +150,22 @@ impl GenericClient for Client { self.query_raw(statement, params).await } + async fn query_with_param_types( + &self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result, Error> { + self.query_with_param_types(statement, params).await + } + + async fn query_raw_with_param_types( + &self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result { + self.query_raw_with_param_types(statement, params).await + } + async fn prepare(&self, query: &str) -> Result { self.prepare(query).await } @@ -222,6 +252,22 @@ impl GenericClient for Transaction<'_> { self.query_raw(statement, params).await } + async fn query_with_param_types( + &self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result, Error> { + self.query_with_param_types(statement, params).await + } + + async fn query_raw_with_param_types( + &self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result { + self.query_raw_with_param_types(statement, params).await + } + async fn prepare(&self, query: &str) -> Result { self.prepare(query).await } diff --git a/tokio-postgres/src/prepare.rs b/tokio-postgres/src/prepare.rs index 07fb45694..1d9bacb16 100644 --- a/tokio-postgres/src/prepare.rs +++ b/tokio-postgres/src/prepare.rs @@ -131,7 +131,7 @@ fn encode(client: &InnerClient, name: &str, query: &str, types: &[Type]) -> Resu }) } -async fn get_type(client: &Arc, oid: Oid) -> Result { +pub(crate) async fn get_type(client: &Arc, oid: Oid) -> Result { if let Some(type_) = Type::from_oid(oid) { return Ok(type_); } diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index e6e1d00a8..b9cc66405 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -1,17 +1,21 @@ use crate::client::{InnerClient, Responses}; use crate::codec::FrontendMessage; use crate::connection::RequestMessages; +use crate::prepare::get_type; use crate::types::{BorrowToSql, IsNull}; -use crate::{Error, Portal, Row, Statement}; +use crate::{Column, Error, Portal, Row, Statement}; use bytes::{Bytes, BytesMut}; +use fallible_iterator::FallibleIterator; use futures_util::{ready, Stream}; use log::{debug, log_enabled, Level}; use pin_project_lite::pin_project; -use postgres_protocol::message::backend::{CommandCompleteBody, Message}; +use postgres_protocol::message::backend::{CommandCompleteBody, Message, RowDescriptionBody}; use postgres_protocol::message::frontend; +use postgres_types::Type; use std::fmt; use std::marker::PhantomPinned; use std::pin::Pin; +use std::sync::Arc; use std::task::{Context, Poll}; struct BorrowToSqlParamsDebug<'a, T>(&'a [T]); @@ -50,13 +54,125 @@ where }; let responses = start(client, buf).await?; Ok(RowStream { - statement, + statement: statement, responses, rows_affected: None, _p: PhantomPinned, }) } +enum QueryProcessingState { + Empty, + ParseCompleted, + BindCompleted, + ParameterDescribed, + Final(Vec), +} + +/// State machine for processing messages for `query_with_param_types`. +impl QueryProcessingState { + pub async fn process_message( + self, + client: &Arc, + message: Message, + ) -> Result { + match (self, message) { + (QueryProcessingState::Empty, Message::ParseComplete) => { + Ok(QueryProcessingState::ParseCompleted) + } + (QueryProcessingState::ParseCompleted, Message::BindComplete) => { + Ok(QueryProcessingState::BindCompleted) + } + (QueryProcessingState::BindCompleted, Message::ParameterDescription(_)) => { + Ok(QueryProcessingState::ParameterDescribed) + } + ( + QueryProcessingState::ParameterDescribed, + Message::RowDescription(row_description), + ) => Self::form_final(client, Some(row_description)).await, + (QueryProcessingState::ParameterDescribed, Message::NoData) => { + Self::form_final(client, None).await + } + (_, Message::ErrorResponse(body)) => Err(Error::db(body)), + _ => Err(Error::unexpected_message()), + } + } + + async fn form_final( + client: &Arc, + row_description: Option, + ) -> Result { + let mut columns = vec![]; + if let Some(row_description) = row_description { + let mut it = row_description.fields(); + while let Some(field) = it.next().map_err(Error::parse)? { + let type_ = get_type(client, field.type_oid()).await?; + let column = Column { + name: field.name().to_string(), + table_oid: Some(field.table_oid()).filter(|n| *n != 0), + column_id: Some(field.column_id()).filter(|n| *n != 0), + r#type: type_, + }; + columns.push(column); + } + } + + Ok(Self::Final(columns)) + } +} + +pub async fn query_with_param_types<'a, P, I>( + client: &Arc, + query: &str, + params: I, +) -> Result +where + P: BorrowToSql, + I: IntoIterator, + I::IntoIter: ExactSizeIterator, +{ + let (params, param_types): (Vec<_>, Vec<_>) = params.into_iter().unzip(); + + let params = params.into_iter(); + + let param_oids = param_types.iter().map(|t| t.oid()).collect::>(); + + let params = params.into_iter(); + + let buf = client.with_buf(|buf| { + frontend::parse("", query, param_oids.into_iter(), buf).map_err(Error::parse)?; + + encode_bind_with_statement_name_and_param_types("", ¶m_types, params, "", buf)?; + + frontend::describe(b'S', "", buf).map_err(Error::encode)?; + + frontend::execute("", 0, buf).map_err(Error::encode)?; + + frontend::sync(buf); + + Ok(buf.split().freeze()) + })?; + + let mut responses = client.send(RequestMessages::Single(FrontendMessage::Raw(buf)))?; + + let mut state = QueryProcessingState::Empty; + + loop { + let message = responses.next().await?; + + state = state.process_message(client, message).await?; + + if let QueryProcessingState::Final(columns) = state { + return Ok(RowStream { + statement: Statement::unnamed(vec![], columns), + responses, + rows_affected: None, + _p: PhantomPinned, + }); + } + } +} + pub async fn query_portal( client: &InnerClient, portal: &Portal, @@ -164,7 +280,27 @@ where I: IntoIterator, I::IntoIter: ExactSizeIterator, { - let param_types = statement.params(); + encode_bind_with_statement_name_and_param_types( + statement.name(), + statement.params(), + params, + portal, + buf, + ) +} + +fn encode_bind_with_statement_name_and_param_types( + statement_name: &str, + param_types: &[Type], + params: I, + portal: &str, + buf: &mut BytesMut, +) -> Result<(), Error> +where + P: BorrowToSql, + I: IntoIterator, + I::IntoIter: ExactSizeIterator, +{ let params = params.into_iter(); if param_types.len() != params.len() { @@ -181,7 +317,7 @@ where let mut error_idx = 0; let r = frontend::bind( portal, - statement.name(), + statement_name, param_formats, params.zip(param_types).enumerate(), |(idx, (param, ty)), buf| match param.borrow_to_sql().to_sql_checked(ty, buf) { diff --git a/tokio-postgres/src/statement.rs b/tokio-postgres/src/statement.rs index c5d657738..2b88ecd3b 100644 --- a/tokio-postgres/src/statement.rs +++ b/tokio-postgres/src/statement.rs @@ -14,6 +14,10 @@ struct StatementInner { impl Drop for StatementInner { fn drop(&mut self) { + if self.name.is_empty() { + // 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(); @@ -46,6 +50,15 @@ impl Statement { })) } + pub(crate) fn unnamed(params: Vec, columns: Vec) -> Statement { + Statement(Arc::new(StatementInner { + client: Weak::new(), + name: String::new(), + params, + columns, + })) + } + pub(crate) fn name(&self) -> &str { &self.0.name } diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index 96a324652..5a6094b56 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -227,6 +227,33 @@ impl<'a> Transaction<'a> { query::query_portal(self.client.inner(), portal, max_rows).await } + /// Like `Client::query_with_param_types`. + pub async fn query_with_param_types( + &self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result, Error> { + self.query_raw_with_param_types(statement, params) + .await? + .try_collect() + .await + } + + /// Like `Client::query_raw_with_param_types`. + pub async fn query_raw_with_param_types( + &self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result { + fn slice_iter<'a>( + s: &'a [(&'a (dyn ToSql + Sync), Type)], + ) -> impl ExactSizeIterator + 'a { + s.iter() + .map(|(param, param_type)| (*param as _, param_type.clone())) + } + query::query_with_param_types(self.client.inner(), statement, slice_iter(params)).await + } + /// Like `Client::copy_in`. pub async fn copy_in(&self, statement: &T) -> Result, Error> where diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index 737f46631..925c99206 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -952,3 +952,109 @@ async fn deferred_constraint() { .await .unwrap_err(); } + +#[tokio::test] +async fn query_with_param_types_no_transaction() { + let client = connect("user=postgres").await; + + client + .batch_execute( + " + CREATE TEMPORARY TABLE foo ( + name TEXT, + age INT + ); + INSERT INTO foo (name, age) VALUES ('alice', 20), ('bob', 30), ('carol', 40); + ", + ) + .await + .unwrap(); + + let rows: Vec = client + .query_with_param_types( + "SELECT name, age, 'literal', 5 FROM foo WHERE name <> $1 AND age < $2 ORDER BY age", + &[(&"alice", Type::TEXT), (&50i32, Type::INT4)], + ) + .await + .unwrap(); + + assert_eq!(rows.len(), 2); + let first_row = &rows[0]; + assert_eq!(first_row.get::<_, &str>(0), "bob"); + assert_eq!(first_row.get::<_, i32>(1), 30); + assert_eq!(first_row.get::<_, &str>(2), "literal"); + assert_eq!(first_row.get::<_, i32>(3), 5); + + let second_row = &rows[1]; + assert_eq!(second_row.get::<_, &str>(0), "carol"); + assert_eq!(second_row.get::<_, i32>(1), 40); + assert_eq!(second_row.get::<_, &str>(2), "literal"); + assert_eq!(second_row.get::<_, i32>(3), 5); +} + +#[tokio::test] +async fn query_with_param_types_with_transaction() { + let mut client = connect("user=postgres").await; + + client + .batch_execute( + " + CREATE TEMPORARY TABLE foo ( + name TEXT, + age INT + ); + ", + ) + .await + .unwrap(); + + let transaction = client.transaction().await.unwrap(); + + let rows: Vec = transaction + .query_with_param_types( + "INSERT INTO foo (name, age) VALUES ($1, $2), ($3, $4), ($5, $6) returning name, age", + &[ + (&"alice", Type::TEXT), + (&20i32, Type::INT4), + (&"bob", Type::TEXT), + (&30i32, Type::INT4), + (&"carol", Type::TEXT), + (&40i32, Type::INT4), + ], + ) + .await + .unwrap(); + let inserted_values: Vec<(String, i32)> = rows + .iter() + .map(|row| (row.get::<_, String>(0), row.get::<_, i32>(1))) + .collect(); + assert_eq!( + inserted_values, + [ + ("alice".to_string(), 20), + ("bob".to_string(), 30), + ("carol".to_string(), 40) + ] + ); + + let rows: Vec = transaction + .query_with_param_types( + "SELECT name, age, 'literal', 5 FROM foo WHERE name <> $1 AND age < $2 ORDER BY age", + &[(&"alice", Type::TEXT), (&50i32, Type::INT4)], + ) + .await + .unwrap(); + + assert_eq!(rows.len(), 2); + let first_row = &rows[0]; + assert_eq!(first_row.get::<_, &str>(0), "bob"); + assert_eq!(first_row.get::<_, i32>(1), 30); + assert_eq!(first_row.get::<_, &str>(2), "literal"); + assert_eq!(first_row.get::<_, i32>(3), 5); + + let second_row = &rows[1]; + assert_eq!(second_row.get::<_, &str>(0), "carol"); + assert_eq!(second_row.get::<_, i32>(1), 40); + assert_eq!(second_row.get::<_, &str>(2), "literal"); + assert_eq!(second_row.get::<_, i32>(3), 5); +} From 84994dad1aa9c3ef5c813b95c86c80dbfa4b7f0d Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Sat, 6 Jul 2024 11:23:26 -0400 Subject: [PATCH 343/420] Derive Clone for Row --- postgres-protocol/src/message/backend.rs | 2 +- tokio-postgres/src/row.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/postgres-protocol/src/message/backend.rs b/postgres-protocol/src/message/backend.rs index 1b5be1098..c4439b26a 100644 --- a/postgres-protocol/src/message/backend.rs +++ b/postgres-protocol/src/message/backend.rs @@ -524,7 +524,7 @@ impl CopyOutResponseBody { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct DataRowBody { storage: Bytes, len: u16, diff --git a/tokio-postgres/src/row.rs b/tokio-postgres/src/row.rs index 3c79de603..767c26921 100644 --- a/tokio-postgres/src/row.rs +++ b/tokio-postgres/src/row.rs @@ -95,6 +95,7 @@ where } /// A row of data returned from the database by a query. +#[derive(Clone)] pub struct Row { statement: Statement, body: DataRowBody, From 2b1949dd2f8745fcfaefe4b5e228684c25997265 Mon Sep 17 00:00:00 2001 From: Sidney Cammeresi Date: Sat, 6 Jul 2024 11:00:41 -0700 Subject: [PATCH 344/420] impl Debug for Statement The lack of this common trait bound caused some unpleasantness. For example, the following didn't compile: let x = OnceLock::new(); let stmt = db.prepare(...)?; x.set(stmt).expect(...); // returns Result<(), T=Statement> where T: Debug --- tokio-postgres/src/statement.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tokio-postgres/src/statement.rs b/tokio-postgres/src/statement.rs index c5d657738..4955d3b41 100644 --- a/tokio-postgres/src/statement.rs +++ b/tokio-postgres/src/statement.rs @@ -61,6 +61,16 @@ impl Statement { } } +impl std::fmt::Debug for Statement { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + f.debug_struct("Statement") + .field("name", &self.0.name) + .field("params", &self.0.params) + .field("columns", &self.0.columns) + .finish_non_exhaustive() + } +} + /// Information about a column of a query. #[derive(Debug)] pub struct Column { From 1f312194928c5a385d51d52e5d13ca59d3dc1b43 Mon Sep 17 00:00:00 2001 From: Sidney Cammeresi Date: Sat, 6 Jul 2024 12:29:09 -0700 Subject: [PATCH 345/420] Fix a few nits pointed out by clippy - ...::max_value() -> ..::MAX - delete explicit import of signed integer types --- postgres-protocol/src/lib.rs | 2 +- postgres-types/src/lib.rs | 2 +- postgres-types/src/special.rs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/postgres-protocol/src/lib.rs b/postgres-protocol/src/lib.rs index 83d9bf55c..e0de3b6c6 100644 --- a/postgres-protocol/src/lib.rs +++ b/postgres-protocol/src/lib.rs @@ -60,7 +60,7 @@ macro_rules! from_usize { impl FromUsize for $t { #[inline] fn from_usize(x: usize) -> io::Result<$t> { - if x > <$t>::max_value() as usize { + if x > <$t>::MAX as usize { Err(io::Error::new( io::ErrorKind::InvalidInput, "value too large to transmit", diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 2f02f6e5f..492039766 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -1222,7 +1222,7 @@ impl ToSql for IpAddr { } fn downcast(len: usize) -> Result> { - if len > i32::max_value() as usize { + if len > i32::MAX as usize { Err("value too large to transmit".into()) } else { Ok(len as i32) diff --git a/postgres-types/src/special.rs b/postgres-types/src/special.rs index 1a865287e..d8541bf0e 100644 --- a/postgres-types/src/special.rs +++ b/postgres-types/src/special.rs @@ -1,7 +1,6 @@ use bytes::BytesMut; use postgres_protocol::types; use std::error::Error; -use std::{i32, i64}; use crate::{FromSql, IsNull, ToSql, Type}; From 263b0068af39072bc7be05b6500e47f263cbd43e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 6 Jul 2024 19:21:37 -0400 Subject: [PATCH 346/420] Handle non-UTF8 error fields --- postgres-protocol/src/message/backend.rs | 10 +++++-- tokio-postgres/src/error/mod.rs | 37 ++++++++++++------------ 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/postgres-protocol/src/message/backend.rs b/postgres-protocol/src/message/backend.rs index c4439b26a..73b169288 100644 --- a/postgres-protocol/src/message/backend.rs +++ b/postgres-protocol/src/message/backend.rs @@ -633,7 +633,7 @@ impl<'a> FallibleIterator for ErrorFields<'a> { } let value_end = find_null(self.buf, 0)?; - let value = get_str(&self.buf[..value_end])?; + let value = &self.buf[..value_end]; self.buf = &self.buf[value_end + 1..]; Ok(Some(ErrorField { type_, value })) @@ -642,7 +642,7 @@ impl<'a> FallibleIterator for ErrorFields<'a> { pub struct ErrorField<'a> { type_: u8, - value: &'a str, + value: &'a [u8], } impl<'a> ErrorField<'a> { @@ -652,7 +652,13 @@ impl<'a> ErrorField<'a> { } #[inline] + #[deprecated(note = "use value_bytes instead", since = "0.6.7")] pub fn value(&self) -> &str { + str::from_utf8(self.value).expect("error field value contained non-UTF8 bytes") + } + + #[inline] + pub fn value_bytes(&self) -> &[u8] { self.value } } diff --git a/tokio-postgres/src/error/mod.rs b/tokio-postgres/src/error/mod.rs index f1e2644c6..75664d258 100644 --- a/tokio-postgres/src/error/mod.rs +++ b/tokio-postgres/src/error/mod.rs @@ -107,14 +107,15 @@ impl DbError { let mut routine = None; while let Some(field) = fields.next()? { + let value = String::from_utf8_lossy(field.value_bytes()); match field.type_() { - b'S' => severity = Some(field.value().to_owned()), - b'C' => code = Some(SqlState::from_code(field.value())), - b'M' => message = Some(field.value().to_owned()), - b'D' => detail = Some(field.value().to_owned()), - b'H' => hint = Some(field.value().to_owned()), + b'S' => severity = Some(value.into_owned()), + b'C' => code = Some(SqlState::from_code(&value)), + b'M' => message = Some(value.into_owned()), + b'D' => detail = Some(value.into_owned()), + b'H' => hint = Some(value.into_owned()), b'P' => { - normal_position = Some(field.value().parse::().map_err(|_| { + normal_position = Some(value.parse::().map_err(|_| { io::Error::new( io::ErrorKind::InvalidInput, "`P` field did not contain an integer", @@ -122,32 +123,32 @@ impl DbError { })?); } b'p' => { - internal_position = Some(field.value().parse::().map_err(|_| { + internal_position = Some(value.parse::().map_err(|_| { io::Error::new( io::ErrorKind::InvalidInput, "`p` field did not contain an integer", ) })?); } - b'q' => internal_query = Some(field.value().to_owned()), - b'W' => where_ = Some(field.value().to_owned()), - b's' => schema = Some(field.value().to_owned()), - b't' => table = Some(field.value().to_owned()), - b'c' => column = Some(field.value().to_owned()), - b'd' => datatype = Some(field.value().to_owned()), - b'n' => constraint = Some(field.value().to_owned()), - b'F' => file = Some(field.value().to_owned()), + b'q' => internal_query = Some(value.into_owned()), + b'W' => where_ = Some(value.into_owned()), + b's' => schema = Some(value.into_owned()), + b't' => table = Some(value.into_owned()), + b'c' => column = Some(value.into_owned()), + b'd' => datatype = Some(value.into_owned()), + b'n' => constraint = Some(value.into_owned()), + b'F' => file = Some(value.into_owned()), b'L' => { - line = Some(field.value().parse::().map_err(|_| { + line = Some(value.parse::().map_err(|_| { io::Error::new( io::ErrorKind::InvalidInput, "`L` field did not contain an integer", ) })?); } - b'R' => routine = Some(field.value().to_owned()), + b'R' => routine = Some(value.into_owned()), b'V' => { - parsed_severity = Some(Severity::from_str(field.value()).ok_or_else(|| { + parsed_severity = Some(Severity::from_str(&value).ok_or_else(|| { io::Error::new( io::ErrorKind::InvalidInput, "`V` field contained an invalid value", From cfd91632be877543a7e19e7a05816ed5d241b559 Mon Sep 17 00:00:00 2001 From: Dane Rigby Date: Sun, 7 Jul 2024 13:56:35 -0500 Subject: [PATCH 347/420] PR Fix: Only use single clone for RowDescription --- tokio-postgres/src/simple_query.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tokio-postgres/src/simple_query.rs b/tokio-postgres/src/simple_query.rs index 86af8e739..b6500260e 100644 --- a/tokio-postgres/src/simple_query.rs +++ b/tokio-postgres/src/simple_query.rs @@ -101,9 +101,9 @@ impl Stream for SimpleQueryStream { .map_err(Error::parse)? .into(); - *this.columns = Some(columns.clone()); + *this.columns = Some(columns); Poll::Ready(Some(Ok(SimpleQueryMessage::RowDescription( - columns.clone(), + this.columns.as_ref().unwrap().clone(), )))) } Message::DataRow(body) => { From 3f8f5ded337a0122959f6e4a3dc9343bf6c6ee70 Mon Sep 17 00:00:00 2001 From: Ramnivas Laddad Date: Sun, 7 Jul 2024 16:21:40 -0700 Subject: [PATCH 348/420] Replace the state machine to process messages with a direct match statements --- tokio-postgres/src/query.rs | 101 ++++++++++-------------------------- 1 file changed, 27 insertions(+), 74 deletions(-) diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index b9cc66405..2bdfa14cc 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -9,7 +9,7 @@ use fallible_iterator::FallibleIterator; use futures_util::{ready, Stream}; use log::{debug, log_enabled, Level}; use pin_project_lite::pin_project; -use postgres_protocol::message::backend::{CommandCompleteBody, Message, RowDescriptionBody}; +use postgres_protocol::message::backend::{CommandCompleteBody, Message}; use postgres_protocol::message::frontend; use postgres_types::Type; use std::fmt; @@ -61,66 +61,6 @@ where }) } -enum QueryProcessingState { - Empty, - ParseCompleted, - BindCompleted, - ParameterDescribed, - Final(Vec), -} - -/// State machine for processing messages for `query_with_param_types`. -impl QueryProcessingState { - pub async fn process_message( - self, - client: &Arc, - message: Message, - ) -> Result { - match (self, message) { - (QueryProcessingState::Empty, Message::ParseComplete) => { - Ok(QueryProcessingState::ParseCompleted) - } - (QueryProcessingState::ParseCompleted, Message::BindComplete) => { - Ok(QueryProcessingState::BindCompleted) - } - (QueryProcessingState::BindCompleted, Message::ParameterDescription(_)) => { - Ok(QueryProcessingState::ParameterDescribed) - } - ( - QueryProcessingState::ParameterDescribed, - Message::RowDescription(row_description), - ) => Self::form_final(client, Some(row_description)).await, - (QueryProcessingState::ParameterDescribed, Message::NoData) => { - Self::form_final(client, None).await - } - (_, Message::ErrorResponse(body)) => Err(Error::db(body)), - _ => Err(Error::unexpected_message()), - } - } - - async fn form_final( - client: &Arc, - row_description: Option, - ) -> Result { - let mut columns = vec![]; - if let Some(row_description) = row_description { - let mut it = row_description.fields(); - while let Some(field) = it.next().map_err(Error::parse)? { - let type_ = get_type(client, field.type_oid()).await?; - let column = Column { - name: field.name().to_string(), - table_oid: Some(field.table_oid()).filter(|n| *n != 0), - column_id: Some(field.column_id()).filter(|n| *n != 0), - r#type: type_, - }; - columns.push(column); - } - } - - Ok(Self::Final(columns)) - } -} - pub async fn query_with_param_types<'a, P, I>( client: &Arc, query: &str, @@ -155,20 +95,33 @@ where let mut responses = client.send(RequestMessages::Single(FrontendMessage::Raw(buf)))?; - let mut state = QueryProcessingState::Empty; - loop { - let message = responses.next().await?; - - state = state.process_message(client, message).await?; - - if let QueryProcessingState::Final(columns) = state { - return Ok(RowStream { - statement: Statement::unnamed(vec![], columns), - responses, - rows_affected: None, - _p: PhantomPinned, - }); + match responses.next().await? { + Message::ParseComplete + | Message::BindComplete + | Message::ParameterDescription(_) + | Message::NoData => {} + Message::RowDescription(row_description) => { + let mut columns: Vec = vec![]; + let mut it = row_description.fields(); + while let Some(field) = it.next().map_err(Error::parse)? { + let type_ = get_type(client, field.type_oid()).await?; + let column = Column { + name: field.name().to_string(), + table_oid: Some(field.table_oid()).filter(|n| *n != 0), + column_id: Some(field.column_id()).filter(|n| *n != 0), + r#type: type_, + }; + columns.push(column); + } + return Ok(RowStream { + statement: Statement::unnamed(vec![], columns), + responses, + rows_affected: None, + _p: PhantomPinned, + }); + } + _ => return Err(Error::unexpected_message()), } } } From 74eb4dbf7399cb96500f2b60a2b838805471a26a Mon Sep 17 00:00:00 2001 From: Ramnivas Laddad Date: Sun, 7 Jul 2024 16:43:41 -0700 Subject: [PATCH 349/420] Remove query_raw_with_param_types as per PR feedback --- tokio-postgres/src/client.rs | 56 ++++++---------------------- tokio-postgres/src/generic_client.rs | 23 ------------ tokio-postgres/src/transaction.rs | 20 +--------- 3 files changed, 12 insertions(+), 87 deletions(-) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 431bfa792..e420bcf2f 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -366,8 +366,13 @@ impl Client { /// Like `query`, but requires the types of query parameters to be explicitly specified. /// - /// Compared to `query`, this method allows performing queries without three round trips (for prepare, execute, and close). Thus, - /// this is suitable in environments where prepared statements aren't supported (such as Cloudflare Workers with Hyperdrive). + /// Compared to `query`, this method allows performing queries without three round trips (for + /// prepare, execute, and close) by requiring the caller to specify parameter values along with + /// their Postgres type. Thus, this is suitable in environments where prepared statements aren't + /// supported (such as Cloudflare Workers with Hyperdrive). + /// + /// A statement may contain parameters, specified by `$n`, where `n` is the index of the + /// parameter of the list provided, 1-indexed. /// /// # Examples /// @@ -394,48 +399,6 @@ impl Client { statement: &str, params: &[(&(dyn ToSql + Sync), Type)], ) -> Result, Error> { - self.query_raw_with_param_types(statement, params) - .await? - .try_collect() - .await - } - - /// The maximally flexible version of [`query_with_param_types`]. - /// - /// A statement may contain parameters, specified by `$n`, where `n` is the index of the parameter of the list - /// provided, 1-indexed. - /// - /// The parameters must specify value along with their Postgres type. This allows performing - /// queries without three round trips (for prepare, execute, and close). - /// - /// [`query_with_param_types`]: #method.query_with_param_types - /// - /// # Examples - /// - /// ```no_run - /// # async fn async_main(client: &tokio_postgres::Client) -> Result<(), tokio_postgres::Error> { - /// use tokio_postgres::types::ToSql; - /// use tokio_postgres::types::Type; - /// use futures_util::{pin_mut, TryStreamExt}; - /// - /// let mut it = client.query_raw_with_param_types( - /// "SELECT foo FROM bar WHERE biz = $1 AND baz = $2", - /// &[(&"first param", Type::TEXT), (&2i32, Type::INT4)], - /// ).await?; - /// - /// pin_mut!(it); - /// while let Some(row) = it.try_next().await? { - /// let foo: i32 = row.get("foo"); - /// println!("foo: {}", foo); - /// } - /// # Ok(()) - /// # } - /// ``` - pub async fn query_raw_with_param_types( - &self, - statement: &str, - params: &[(&(dyn ToSql + Sync), Type)], - ) -> Result { fn slice_iter<'a>( s: &'a [(&'a (dyn ToSql + Sync), Type)], ) -> impl ExactSizeIterator + 'a { @@ -443,7 +406,10 @@ impl Client { .map(|(param, param_type)| (*param as _, param_type.clone())) } - query::query_with_param_types(&self.inner, statement, slice_iter(params)).await + query::query_with_param_types(&self.inner, statement, slice_iter(params)) + .await? + .try_collect() + .await } /// Executes a statement, returning the number of rows modified. diff --git a/tokio-postgres/src/generic_client.rs b/tokio-postgres/src/generic_client.rs index 3a0b09233..b892015dc 100644 --- a/tokio-postgres/src/generic_client.rs +++ b/tokio-postgres/src/generic_client.rs @@ -63,13 +63,6 @@ pub trait GenericClient: private::Sealed { params: &[(&(dyn ToSql + Sync), Type)], ) -> Result, Error>; - /// Like `Client::query_raw_with_param_types`. - async fn query_raw_with_param_types( - &self, - statement: &str, - params: &[(&(dyn ToSql + Sync), Type)], - ) -> Result; - /// Like `Client::prepare`. async fn prepare(&self, query: &str) -> Result; @@ -158,14 +151,6 @@ impl GenericClient for Client { self.query_with_param_types(statement, params).await } - async fn query_raw_with_param_types( - &self, - statement: &str, - params: &[(&(dyn ToSql + Sync), Type)], - ) -> Result { - self.query_raw_with_param_types(statement, params).await - } - async fn prepare(&self, query: &str) -> Result { self.prepare(query).await } @@ -260,14 +245,6 @@ impl GenericClient for Transaction<'_> { self.query_with_param_types(statement, params).await } - async fn query_raw_with_param_types( - &self, - statement: &str, - params: &[(&(dyn ToSql + Sync), Type)], - ) -> Result { - self.query_raw_with_param_types(statement, params).await - } - async fn prepare(&self, query: &str) -> Result { self.prepare(query).await } diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index 5a6094b56..8a0ad2224 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -233,25 +233,7 @@ impl<'a> Transaction<'a> { statement: &str, params: &[(&(dyn ToSql + Sync), Type)], ) -> Result, Error> { - self.query_raw_with_param_types(statement, params) - .await? - .try_collect() - .await - } - - /// Like `Client::query_raw_with_param_types`. - pub async fn query_raw_with_param_types( - &self, - statement: &str, - params: &[(&(dyn ToSql + Sync), Type)], - ) -> Result { - fn slice_iter<'a>( - s: &'a [(&'a (dyn ToSql + Sync), Type)], - ) -> impl ExactSizeIterator + 'a { - s.iter() - .map(|(param, param_type)| (*param as _, param_type.clone())) - } - query::query_with_param_types(self.client.inner(), statement, slice_iter(params)).await + self.client.query_with_param_types(statement, params).await } /// Like `Client::copy_in`. From 2647024c660ca27701898325a8772b83bece4982 Mon Sep 17 00:00:00 2001 From: Dane Rigby Date: Sun, 7 Jul 2024 21:30:23 -0500 Subject: [PATCH 350/420] PR Fix: Clone first then move --- tokio-postgres/src/simple_query.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tokio-postgres/src/simple_query.rs b/tokio-postgres/src/simple_query.rs index b6500260e..24473b896 100644 --- a/tokio-postgres/src/simple_query.rs +++ b/tokio-postgres/src/simple_query.rs @@ -101,10 +101,8 @@ impl Stream for SimpleQueryStream { .map_err(Error::parse)? .into(); - *this.columns = Some(columns); - Poll::Ready(Some(Ok(SimpleQueryMessage::RowDescription( - this.columns.as_ref().unwrap().clone(), - )))) + *this.columns = Some(columns.clone()); + Poll::Ready(Some(Ok(SimpleQueryMessage::RowDescription(columns)))) } Message::DataRow(body) => { let row = match &this.columns { From dbd4d02e2f3a367b949e356e9dda40c08272d954 Mon Sep 17 00:00:00 2001 From: Ramnivas Laddad Date: Mon, 8 Jul 2024 17:21:32 -0700 Subject: [PATCH 351/420] Address review comment to rename query_with_param_types to query_typed --- tokio-postgres/src/client.rs | 6 +++--- tokio-postgres/src/generic_client.rs | 12 ++++++------ tokio-postgres/src/query.rs | 2 +- tokio-postgres/src/transaction.rs | 6 +++--- tokio-postgres/tests/test/main.rs | 10 +++++----- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index e420bcf2f..2b29351a5 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -382,7 +382,7 @@ impl Client { /// use tokio_postgres::types::Type; /// use futures_util::{pin_mut, TryStreamExt}; /// - /// let rows = client.query_with_param_types( + /// let rows = client.query_typed( /// "SELECT foo FROM bar WHERE biz = $1 AND baz = $2", /// &[(&"first param", Type::TEXT), (&2i32, Type::INT4)], /// ).await?; @@ -394,7 +394,7 @@ impl Client { /// # Ok(()) /// # } /// ``` - pub async fn query_with_param_types( + pub async fn query_typed( &self, statement: &str, params: &[(&(dyn ToSql + Sync), Type)], @@ -406,7 +406,7 @@ impl Client { .map(|(param, param_type)| (*param as _, param_type.clone())) } - query::query_with_param_types(&self.inner, statement, slice_iter(params)) + query::query_typed(&self.inner, statement, slice_iter(params)) .await? .try_collect() .await diff --git a/tokio-postgres/src/generic_client.rs b/tokio-postgres/src/generic_client.rs index e43bddfea..b91d78064 100644 --- a/tokio-postgres/src/generic_client.rs +++ b/tokio-postgres/src/generic_client.rs @@ -56,8 +56,8 @@ pub trait GenericClient: private::Sealed { I: IntoIterator + Sync + Send, I::IntoIter: ExactSizeIterator; - /// Like [`Client::query_with_param_types`] - async fn query_with_param_types( + /// Like [`Client::query_typed`] + async fn query_typed( &self, statement: &str, params: &[(&(dyn ToSql + Sync), Type)], @@ -146,12 +146,12 @@ impl GenericClient for Client { self.query_raw(statement, params).await } - async fn query_with_param_types( + async fn query_typed( &self, statement: &str, params: &[(&(dyn ToSql + Sync), Type)], ) -> Result, Error> { - self.query_with_param_types(statement, params).await + self.query_typed(statement, params).await } async fn prepare(&self, query: &str) -> Result { @@ -244,12 +244,12 @@ impl GenericClient for Transaction<'_> { self.query_raw(statement, params).await } - async fn query_with_param_types( + async fn query_typed( &self, statement: &str, params: &[(&(dyn ToSql + Sync), Type)], ) -> Result, Error> { - self.query_with_param_types(statement, params).await + self.query_typed(statement, params).await } async fn prepare(&self, query: &str) -> Result { diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index 2bdfa14cc..b54e095df 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -61,7 +61,7 @@ where }) } -pub async fn query_with_param_types<'a, P, I>( +pub async fn query_typed<'a, P, I>( client: &Arc, query: &str, params: I, diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index 8a0ad2224..3e62b2ac7 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -227,13 +227,13 @@ impl<'a> Transaction<'a> { query::query_portal(self.client.inner(), portal, max_rows).await } - /// Like `Client::query_with_param_types`. - pub async fn query_with_param_types( + /// Like `Client::query_typed`. + pub async fn query_typed( &self, statement: &str, params: &[(&(dyn ToSql + Sync), Type)], ) -> Result, Error> { - self.client.query_with_param_types(statement, params).await + self.client.query_typed(statement, params).await } /// Like `Client::copy_in`. diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index 925c99206..7ddb7a36a 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -954,7 +954,7 @@ async fn deferred_constraint() { } #[tokio::test] -async fn query_with_param_types_no_transaction() { +async fn query_typed_no_transaction() { let client = connect("user=postgres").await; client @@ -971,7 +971,7 @@ async fn query_with_param_types_no_transaction() { .unwrap(); let rows: Vec = client - .query_with_param_types( + .query_typed( "SELECT name, age, 'literal', 5 FROM foo WHERE name <> $1 AND age < $2 ORDER BY age", &[(&"alice", Type::TEXT), (&50i32, Type::INT4)], ) @@ -993,7 +993,7 @@ async fn query_with_param_types_no_transaction() { } #[tokio::test] -async fn query_with_param_types_with_transaction() { +async fn query_typed_with_transaction() { let mut client = connect("user=postgres").await; client @@ -1011,7 +1011,7 @@ async fn query_with_param_types_with_transaction() { let transaction = client.transaction().await.unwrap(); let rows: Vec = transaction - .query_with_param_types( + .query_typed( "INSERT INTO foo (name, age) VALUES ($1, $2), ($3, $4), ($5, $6) returning name, age", &[ (&"alice", Type::TEXT), @@ -1038,7 +1038,7 @@ async fn query_with_param_types_with_transaction() { ); let rows: Vec = transaction - .query_with_param_types( + .query_typed( "SELECT name, age, 'literal', 5 FROM foo WHERE name <> $1 AND age < $2 ORDER BY age", &[(&"alice", Type::TEXT), (&50i32, Type::INT4)], ) From 0fa32471ef2e20b7f2e554d6d97cde3a67f1d494 Mon Sep 17 00:00:00 2001 From: Ramnivas Laddad Date: Tue, 9 Jul 2024 17:59:39 -0700 Subject: [PATCH 352/420] Fix a clippy warning --- 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 b54e095df..e304bbaea 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -54,7 +54,7 @@ where }; let responses = start(client, buf).await?; Ok(RowStream { - statement: statement, + statement, responses, rows_affected: None, _p: PhantomPinned, From 71c836b980799256a7f266195382fc8449fca5e4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 13 Jul 2024 20:45:32 -0400 Subject: [PATCH 353/420] query_typed tweaks --- postgres/src/client.rs | 65 ++++++++++++++++++++++++++++ postgres/src/generic_client.rs | 45 +++++++++++++++++++ postgres/src/transaction.rs | 29 +++++++++++++ tokio-postgres/src/client.rs | 63 +++++++++++++++++---------- tokio-postgres/src/generic_client.rs | 22 ++++++++++ tokio-postgres/src/query.rs | 63 +++++++++++---------------- tokio-postgres/src/transaction.rs | 27 ++++++++---- 7 files changed, 243 insertions(+), 71 deletions(-) diff --git a/postgres/src/client.rs b/postgres/src/client.rs index c8e14cf81..42ce6dec9 100644 --- a/postgres/src/client.rs +++ b/postgres/src/client.rs @@ -257,6 +257,71 @@ impl Client { Ok(RowIter::new(self.connection.as_ref(), stream)) } + /// Like `query`, but requires the types of query parameters to be explicitly specified. + /// + /// Compared to `query`, this method allows performing queries without three round trips (for + /// prepare, execute, and close) by requiring the caller to specify parameter values along with + /// their Postgres type. Thus, this is suitable in environments where prepared statements aren't + /// supported (such as Cloudflare Workers with Hyperdrive). + /// + /// A statement may contain parameters, specified by `$n`, where `n` is the index of the + /// parameter of the list provided, 1-indexed. + pub fn query_typed( + &mut self, + query: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result, Error> { + self.connection + .block_on(self.client.query_typed(query, params)) + } + + /// The maximally flexible version of [`query_typed`]. + /// + /// Compared to `query`, this method allows performing queries without three round trips (for + /// prepare, execute, and close) by requiring the caller to specify parameter values along with + /// their Postgres type. Thus, this is suitable in environments where prepared statements aren't + /// supported (such as Cloudflare Workers with Hyperdrive). + /// + /// A statement may contain parameters, specified by `$n`, where `n` is the index of the + /// parameter of the list provided, 1-indexed. + /// + /// [`query_typed`]: #method.query_typed + /// + /// # Examples + /// ```no_run + /// # use postgres::{Client, NoTls}; + /// use postgres::types::{ToSql, Type}; + /// use fallible_iterator::FallibleIterator; + /// # fn main() -> Result<(), postgres::Error> { + /// # let mut client = Client::connect("host=localhost user=postgres", NoTls)?; + /// + /// let params: Vec<(String, Type)> = vec![ + /// ("first param".into(), Type::TEXT), + /// ("second param".into(), Type::TEXT), + /// ]; + /// let mut it = client.query_typed_raw( + /// "SELECT foo FROM bar WHERE biz = $1 AND baz = $2", + /// params, + /// )?; + /// + /// while let Some(row) = it.next()? { + /// let foo: i32 = row.get("foo"); + /// println!("foo: {}", foo); + /// } + /// # Ok(()) + /// # } + /// ``` + pub fn query_typed_raw(&mut self, query: &str, params: I) -> Result, Error> + where + P: BorrowToSql, + I: IntoIterator, + { + let stream = self + .connection + .block_on(self.client.query_typed_raw(query, params))?; + Ok(RowIter::new(self.connection.as_ref(), stream)) + } + /// Creates a new prepared statement. /// /// Prepared statements can be executed repeatedly, and may contain query parameters (indicated by `$1`, `$2`, etc), diff --git a/postgres/src/generic_client.rs b/postgres/src/generic_client.rs index 12f07465d..7b534867c 100644 --- a/postgres/src/generic_client.rs +++ b/postgres/src/generic_client.rs @@ -44,6 +44,19 @@ pub trait GenericClient: private::Sealed { I: IntoIterator, I::IntoIter: ExactSizeIterator; + /// Like [`Client::query_typed`] + fn query_typed( + &mut self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result, Error>; + + /// Like [`Client::query_typed_raw`] + fn query_typed_raw(&mut self, statement: &str, params: I) -> Result, Error> + where + P: BorrowToSql, + I: IntoIterator + Sync + Send; + /// Like `Client::prepare`. fn prepare(&mut self, query: &str) -> Result; @@ -115,6 +128,22 @@ impl GenericClient for Client { self.query_raw(query, params) } + fn query_typed( + &mut self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result, Error> { + self.query_typed(statement, params) + } + + fn query_typed_raw(&mut self, statement: &str, params: I) -> Result, Error> + where + P: BorrowToSql, + I: IntoIterator + Sync + Send, + { + self.query_typed_raw(statement, params) + } + fn prepare(&mut self, query: &str) -> Result { self.prepare(query) } @@ -195,6 +224,22 @@ impl GenericClient for Transaction<'_> { self.query_raw(query, params) } + fn query_typed( + &mut self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result, Error> { + self.query_typed(statement, params) + } + + fn query_typed_raw(&mut self, statement: &str, params: I) -> Result, Error> + where + P: BorrowToSql, + I: IntoIterator + Sync + Send, + { + self.query_typed_raw(statement, params) + } + fn prepare(&mut self, query: &str) -> Result { self.prepare(query) } diff --git a/postgres/src/transaction.rs b/postgres/src/transaction.rs index 17c49c406..5c8c15973 100644 --- a/postgres/src/transaction.rs +++ b/postgres/src/transaction.rs @@ -115,6 +115,35 @@ impl<'a> Transaction<'a> { Ok(RowIter::new(self.connection.as_ref(), stream)) } + /// Like `Client::query_typed`. + pub fn query_typed( + &mut self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result, Error> { + self.connection.block_on( + self.transaction + .as_ref() + .unwrap() + .query_typed(statement, params), + ) + } + + /// Like `Client::query_typed_raw`. + pub fn query_typed_raw(&mut self, query: &str, params: I) -> Result, Error> + where + P: BorrowToSql, + I: IntoIterator, + { + let stream = self.connection.block_on( + self.transaction + .as_ref() + .unwrap() + .query_typed_raw(query, params), + )?; + Ok(RowIter::new(self.connection.as_ref(), stream)) + } + /// Binds parameters to a statement, creating a "portal". /// /// Portals can be used with the `query_portal` method to page through the results of a query without being forced diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index 2b29351a5..b04f05f88 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -333,7 +333,6 @@ impl Client { /// /// ```no_run /// # async fn async_main(client: &tokio_postgres::Client) -> Result<(), tokio_postgres::Error> { - /// use tokio_postgres::types::ToSql; /// use futures_util::{pin_mut, TryStreamExt}; /// /// let params: Vec = vec![ @@ -373,43 +372,59 @@ impl Client { /// /// A statement may contain parameters, specified by `$n`, where `n` is the index of the /// parameter of the list provided, 1-indexed. + pub async fn query_typed( + &self, + query: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result, Error> { + self.query_typed_raw(query, params.iter().map(|(v, t)| (*v, t.clone()))) + .await? + .try_collect() + .await + } + + /// The maximally flexible version of [`query_typed`]. + /// + /// Compared to `query`, this method allows performing queries without three round trips (for + /// prepare, execute, and close) by requiring the caller to specify parameter values along with + /// their Postgres type. Thus, this is suitable in environments where prepared statements aren't + /// supported (such as Cloudflare Workers with Hyperdrive). + /// + /// A statement may contain parameters, specified by `$n`, where `n` is the index of the + /// parameter of the list provided, 1-indexed. + /// + /// [`query_typed`]: #method.query_typed /// /// # Examples /// /// ```no_run /// # async fn async_main(client: &tokio_postgres::Client) -> Result<(), tokio_postgres::Error> { - /// use tokio_postgres::types::ToSql; - /// use tokio_postgres::types::Type; /// use futures_util::{pin_mut, TryStreamExt}; + /// use tokio_postgres::types::Type; /// - /// let rows = client.query_typed( + /// let params: Vec<(String, Type)> = vec![ + /// ("first param".into(), Type::TEXT), + /// ("second param".into(), Type::TEXT), + /// ]; + /// let mut it = client.query_typed_raw( /// "SELECT foo FROM bar WHERE biz = $1 AND baz = $2", - /// &[(&"first param", Type::TEXT), (&2i32, Type::INT4)], + /// params, /// ).await?; /// - /// for row in rows { - /// let foo: i32 = row.get("foo"); - /// println!("foo: {}", foo); + /// pin_mut!(it); + /// while let Some(row) = it.try_next().await? { + /// let foo: i32 = row.get("foo"); + /// println!("foo: {}", foo); /// } /// # Ok(()) /// # } /// ``` - pub async fn query_typed( - &self, - statement: &str, - params: &[(&(dyn ToSql + Sync), Type)], - ) -> Result, Error> { - fn slice_iter<'a>( - s: &'a [(&'a (dyn ToSql + Sync), Type)], - ) -> impl ExactSizeIterator + 'a { - s.iter() - .map(|(param, param_type)| (*param as _, param_type.clone())) - } - - query::query_typed(&self.inner, statement, slice_iter(params)) - .await? - .try_collect() - .await + pub async fn query_typed_raw(&self, query: &str, params: I) -> Result + where + P: BorrowToSql, + I: IntoIterator, + { + query::query_typed(&self.inner, query, params).await } /// Executes a statement, returning the number of rows modified. diff --git a/tokio-postgres/src/generic_client.rs b/tokio-postgres/src/generic_client.rs index b91d78064..6e7dffeb1 100644 --- a/tokio-postgres/src/generic_client.rs +++ b/tokio-postgres/src/generic_client.rs @@ -63,6 +63,12 @@ pub trait GenericClient: private::Sealed { params: &[(&(dyn ToSql + Sync), Type)], ) -> Result, Error>; + /// Like [`Client::query_typed_raw`] + async fn query_typed_raw(&self, statement: &str, params: I) -> Result + where + P: BorrowToSql, + I: IntoIterator + Sync + Send; + /// Like [`Client::prepare`]. async fn prepare(&self, query: &str) -> Result; @@ -154,6 +160,14 @@ impl GenericClient for Client { self.query_typed(statement, params).await } + async fn query_typed_raw(&self, statement: &str, params: I) -> Result + where + P: BorrowToSql, + I: IntoIterator + Sync + Send, + { + self.query_typed_raw(statement, params).await + } + async fn prepare(&self, query: &str) -> Result { self.prepare(query).await } @@ -252,6 +266,14 @@ impl GenericClient for Transaction<'_> { self.query_typed(statement, params).await } + async fn query_typed_raw(&self, statement: &str, params: I) -> Result + where + P: BorrowToSql, + I: IntoIterator + Sync + Send, + { + self.query_typed_raw(statement, params).await + } + async fn prepare(&self, query: &str) -> Result { self.prepare(query).await } diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index e304bbaea..be42d66b6 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -69,29 +69,21 @@ pub async fn query_typed<'a, P, I>( where P: BorrowToSql, I: IntoIterator, - I::IntoIter: ExactSizeIterator, { - let (params, param_types): (Vec<_>, Vec<_>) = params.into_iter().unzip(); - - let params = params.into_iter(); - - let param_oids = param_types.iter().map(|t| t.oid()).collect::>(); - - let params = params.into_iter(); - - let buf = client.with_buf(|buf| { - frontend::parse("", query, param_oids.into_iter(), buf).map_err(Error::parse)?; - - encode_bind_with_statement_name_and_param_types("", ¶m_types, params, "", buf)?; - - frontend::describe(b'S', "", buf).map_err(Error::encode)?; - - frontend::execute("", 0, buf).map_err(Error::encode)?; + let buf = { + let params = params.into_iter().collect::>(); + let param_oids = params.iter().map(|(_, t)| t.oid()).collect::>(); - frontend::sync(buf); + client.with_buf(|buf| { + frontend::parse("", query, param_oids.into_iter(), buf).map_err(Error::parse)?; + encode_bind_raw("", params, "", buf)?; + frontend::describe(b'S', "", buf).map_err(Error::encode)?; + frontend::execute("", 0, buf).map_err(Error::encode)?; + frontend::sync(buf); - Ok(buf.split().freeze()) - })?; + Ok(buf.split().freeze()) + })? + }; let mut responses = client.send(RequestMessages::Single(FrontendMessage::Raw(buf)))?; @@ -233,47 +225,42 @@ where I: IntoIterator, I::IntoIter: ExactSizeIterator, { - encode_bind_with_statement_name_and_param_types( + let params = params.into_iter(); + if params.len() != statement.params().len() { + return Err(Error::parameters(params.len(), statement.params().len())); + } + + encode_bind_raw( statement.name(), - statement.params(), - params, + params.zip(statement.params().iter().cloned()), portal, buf, ) } -fn encode_bind_with_statement_name_and_param_types( +fn encode_bind_raw( statement_name: &str, - param_types: &[Type], params: I, portal: &str, buf: &mut BytesMut, ) -> Result<(), Error> where P: BorrowToSql, - I: IntoIterator, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { - let params = params.into_iter(); - - if param_types.len() != params.len() { - return Err(Error::parameters(params.len(), param_types.len())); - } - let (param_formats, params): (Vec<_>, Vec<_>) = params - .zip(param_types.iter()) - .map(|(p, ty)| (p.borrow_to_sql().encode_format(ty) as i16, p)) + .into_iter() + .map(|(p, ty)| (p.borrow_to_sql().encode_format(&ty) as i16, (p, ty))) .unzip(); - let params = params.into_iter(); - let mut error_idx = 0; let r = frontend::bind( portal, statement_name, param_formats, - params.zip(param_types).enumerate(), - |(idx, (param, ty)), buf| match param.borrow_to_sql().to_sql_checked(ty, buf) { + params.into_iter().enumerate(), + |(idx, (param, ty)), buf| match param.borrow_to_sql().to_sql_checked(&ty, buf) { Ok(IsNull::No) => Ok(postgres_protocol::IsNull::No), Ok(IsNull::Yes) => Ok(postgres_protocol::IsNull::Yes), Err(e) => { diff --git a/tokio-postgres/src/transaction.rs b/tokio-postgres/src/transaction.rs index 3e62b2ac7..17a50b60f 100644 --- a/tokio-postgres/src/transaction.rs +++ b/tokio-postgres/src/transaction.rs @@ -149,6 +149,24 @@ impl<'a> Transaction<'a> { self.client.query_raw(statement, params).await } + /// Like `Client::query_typed`. + pub async fn query_typed( + &self, + statement: &str, + params: &[(&(dyn ToSql + Sync), Type)], + ) -> Result, Error> { + self.client.query_typed(statement, params).await + } + + /// Like `Client::query_typed_raw`. + pub async fn query_typed_raw(&self, query: &str, params: I) -> Result + where + P: BorrowToSql, + I: IntoIterator, + { + self.client.query_typed_raw(query, params).await + } + /// Like `Client::execute`. pub async fn execute( &self, @@ -227,15 +245,6 @@ impl<'a> Transaction<'a> { query::query_portal(self.client.inner(), portal, max_rows).await } - /// Like `Client::query_typed`. - pub async fn query_typed( - &self, - statement: &str, - params: &[(&(dyn ToSql + Sync), Type)], - ) -> Result, Error> { - self.client.query_typed(statement, params).await - } - /// Like `Client::copy_in`. pub async fn copy_in(&self, statement: &T) -> Result, Error> where From a0b2d701ebee8fd5c5b3d6ee5cf0cde5d7f36a65 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 21 Jul 2024 20:04:35 -0400 Subject: [PATCH 354/420] Fix cancellation of TransactionBuilder::start --- tokio-postgres/src/client.rs | 42 ++--------------------- tokio-postgres/src/transaction_builder.rs | 40 +++++++++++++++++++-- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/tokio-postgres/src/client.rs b/tokio-postgres/src/client.rs index b04f05f88..92eabde36 100644 --- a/tokio-postgres/src/client.rs +++ b/tokio-postgres/src/client.rs @@ -1,4 +1,4 @@ -use crate::codec::{BackendMessages, FrontendMessage}; +use crate::codec::BackendMessages; use crate::config::SslMode; use crate::connection::{Request, RequestMessages}; use crate::copy_out::CopyOutStream; @@ -21,7 +21,7 @@ use fallible_iterator::FallibleIterator; use futures_channel::mpsc; use futures_util::{future, pin_mut, ready, StreamExt, TryStreamExt}; use parking_lot::Mutex; -use postgres_protocol::message::{backend::Message, frontend}; +use postgres_protocol::message::backend::Message; use postgres_types::BorrowToSql; use std::collections::HashMap; use std::fmt; @@ -532,43 +532,7 @@ impl Client { /// /// The transaction will roll back by default - use the `commit` method to commit it. pub async fn transaction(&mut self) -> Result, Error> { - struct RollbackIfNotDone<'me> { - client: &'me Client, - done: bool, - } - - impl<'a> Drop for RollbackIfNotDone<'a> { - fn drop(&mut self) { - if self.done { - return; - } - - let buf = self.client.inner().with_buf(|buf| { - frontend::query("ROLLBACK", buf).unwrap(); - buf.split().freeze() - }); - let _ = self - .client - .inner() - .send(RequestMessages::Single(FrontendMessage::Raw(buf))); - } - } - - // This is done, as `Future` created by this method can be dropped after - // `RequestMessages` is synchronously send to the `Connection` by - // `batch_execute()`, but before `Responses` is asynchronously polled to - // completion. In that case `Transaction` won't be created and thus - // won't be rolled back. - { - let mut cleaner = RollbackIfNotDone { - client: self, - done: false, - }; - self.batch_execute("BEGIN").await?; - cleaner.done = true; - } - - Ok(Transaction::new(self)) + self.build_transaction().start().await } /// Returns a builder for a transaction with custom settings. diff --git a/tokio-postgres/src/transaction_builder.rs b/tokio-postgres/src/transaction_builder.rs index 9718ac588..93e9e9801 100644 --- a/tokio-postgres/src/transaction_builder.rs +++ b/tokio-postgres/src/transaction_builder.rs @@ -1,4 +1,6 @@ -use crate::{Client, Error, Transaction}; +use postgres_protocol::message::frontend; + +use crate::{codec::FrontendMessage, connection::RequestMessages, Client, Error, Transaction}; /// The isolation level of a database transaction. #[derive(Debug, Copy, Clone)] @@ -106,7 +108,41 @@ impl<'a> TransactionBuilder<'a> { query.push_str(s); } - self.client.batch_execute(&query).await?; + struct RollbackIfNotDone<'me> { + client: &'me Client, + done: bool, + } + + impl<'a> Drop for RollbackIfNotDone<'a> { + fn drop(&mut self) { + if self.done { + return; + } + + let buf = self.client.inner().with_buf(|buf| { + frontend::query("ROLLBACK", buf).unwrap(); + buf.split().freeze() + }); + let _ = self + .client + .inner() + .send(RequestMessages::Single(FrontendMessage::Raw(buf))); + } + } + + // This is done as `Future` created by this method can be dropped after + // `RequestMessages` is synchronously send to the `Connection` by + // `batch_execute()`, but before `Responses` is asynchronously polled to + // completion. In that case `Transaction` won't be created and thus + // won't be rolled back. + { + let mut cleaner = RollbackIfNotDone { + client: self.client, + done: false, + }; + self.client.batch_execute(&query).await?; + cleaner.done = true; + } Ok(Transaction::new(self.client)) } From c3580774fcdc4597dac81e1128ef8bef1e6ff3a7 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 21 Jul 2024 20:23:50 -0400 Subject: [PATCH 355/420] Release postgres-protocol v0.6.7 --- postgres-protocol/CHANGELOG.md | 17 ++++++++++++++++- postgres-protocol/Cargo.toml | 2 +- postgres-types/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/postgres-protocol/CHANGELOG.md b/postgres-protocol/CHANGELOG.md index 1c371675c..54dce91b0 100644 --- a/postgres-protocol/CHANGELOG.md +++ b/postgres-protocol/CHANGELOG.md @@ -1,6 +1,21 @@ # Change Log -## v0.6.6 -2023-08-19 +## v0.6.7 - 2024-07-21 + +### Deprecated + +* Deprecated `ErrorField::value`. + +### Added + +* Added a `Clone` implementation for `DataRowBody`. +* Added `ErrorField::value_bytes`. + +### Changed + +* Upgraded `base64`. + +## v0.6.6 - 2023-08-19 ### Added diff --git a/postgres-protocol/Cargo.toml b/postgres-protocol/Cargo.toml index a8a130495..49cf2d59c 100644 --- a/postgres-protocol/Cargo.toml +++ b/postgres-protocol/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-protocol" -version = "0.6.6" +version = "0.6.7" authors = ["Steven Fackler "] edition = "2018" description = "Low level Postgres protocol APIs" diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 33296db2c..984fd186f 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -31,7 +31,7 @@ with-time-0_3 = ["time-03"] [dependencies] bytes = "1.0" fallible-iterator = "0.2" -postgres-protocol = { version = "0.6.5", path = "../postgres-protocol" } +postgres-protocol = { version = "0.6.7", path = "../postgres-protocol" } postgres-derive = { version = "0.4.5", optional = true, path = "../postgres-derive" } array-init = { version = "2", optional = true } diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 2e080cfb2..92f4ee696 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -54,7 +54,7 @@ parking_lot = "0.12" percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.11" -postgres-protocol = { version = "0.6.6", path = "../postgres-protocol" } +postgres-protocol = { version = "0.6.7", path = "../postgres-protocol" } postgres-types = { version = "0.2.5", path = "../postgres-types" } tokio = { version = "1.27", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } From 6b4566b132ca4a81c06eaf35eb63318a69360f48 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 21 Jul 2024 20:28:22 -0400 Subject: [PATCH 356/420] Release postgres-types v0.2.7 --- postgres-types/CHANGELOG.md | 8 ++++++++ postgres-types/Cargo.toml | 2 +- tokio-postgres/Cargo.toml | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index 157a2cc7d..1e5cd31d8 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -2,9 +2,17 @@ ## Unreleased +## v0.2.7 - 2024-07-21 + +### Added + +* Added `Default` implementation for `Json`. +* Added a `js` feature for WASM compatibility. + ### Changed * `FromStr` implementation for `PgLsn` no longer allocates a `Vec` when splitting an lsn string on it's `/`. +* The `eui48-1` feature no longer enables default features of the `eui48` library. ## v0.2.6 - 2023-08-19 diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index 984fd186f..e2d21b358 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres-types" -version = "0.2.6" +version = "0.2.7" authors = ["Steven Fackler "] edition = "2018" license = "MIT OR Apache-2.0" diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index 92f4ee696..f762b1184 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -55,7 +55,7 @@ percent-encoding = "2.0" pin-project-lite = "0.2" phf = "0.11" postgres-protocol = { version = "0.6.7", path = "../postgres-protocol" } -postgres-types = { version = "0.2.5", path = "../postgres-types" } +postgres-types = { version = "0.2.7", path = "../postgres-types" } tokio = { version = "1.27", features = ["io-util"] } tokio-util = { version = "0.7", features = ["codec"] } rand = "0.8.5" From 92266188e8fd081be8e29d425b9fd334d2039196 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 21 Jul 2024 20:36:18 -0400 Subject: [PATCH 357/420] Release tokio-postgres v0.7.11 --- postgres-native-tls/Cargo.toml | 2 +- postgres-openssl/Cargo.toml | 2 +- postgres/Cargo.toml | 2 +- tokio-postgres/CHANGELOG.md | 24 +++++++++++++++++++++--- tokio-postgres/Cargo.toml | 2 +- 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index 936eeeaa4..6c17d0889 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -19,7 +19,7 @@ runtime = ["tokio-postgres/runtime"] native-tls = "0.2" tokio = "1.0" tokio-native-tls = "0.3" -tokio-postgres = { version = "0.7.0", path = "../tokio-postgres", default-features = false } +tokio-postgres = { version = "0.7.11", path = "../tokio-postgres", default-features = false } [dev-dependencies] futures-util = "0.3" diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index b7ebd3385..7c19070bf 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -19,7 +19,7 @@ runtime = ["tokio-postgres/runtime"] openssl = "0.10" tokio = "1.0" tokio-openssl = "0.6" -tokio-postgres = { version = "0.7.0", path = "../tokio-postgres", default-features = false } +tokio-postgres = { version = "0.7.11", path = "../tokio-postgres", default-features = false } [dev-dependencies] futures-util = "0.3" diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index 2ff3c875e..f1dc3c685 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -40,7 +40,7 @@ bytes = "1.0" fallible-iterator = "0.2" futures-util = { version = "0.3.14", features = ["sink"] } log = "0.4" -tokio-postgres = { version = "0.7.10", path = "../tokio-postgres" } +tokio-postgres = { version = "0.7.11", 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 775c22e34..e0be26296 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -2,10 +2,28 @@ ## Unreleased +## v0.7.11 - 2024-07-21 + +### Fixed + +* Fixed handling of non-UTF8 error fields which can be sent after failed handshakes. +* Fixed cancellation handling of `TransactionBuilder::start` futures. + +### Added + +* Added `table_oid` and `field_id` fields to `Columns` struct of prepared statements. +* Added `GenericClient::simple_query`. +* Added `#[track_caller]` to `Row::get` and `SimpleQueryRow::get`. +* Added `TargetSessionAttrs::ReadOnly`. +* Added `Debug` implementation for `Statement`. +* Added `Clone` implementation for `Row`. +* Added `SimpleQueryMessage::RowDescription`. +* Added `{Client, Transaction, GenericClient}::query_typed`. + +### Changed + * Disable `rustc-serialize` compatibility of `eui48-1` dependency -* Remove tests for `eui48-04` -* Add `table_oid` and `field_id` fields to `Columns` struct of prepared statements. -* Add `GenericClient::simple_query`. +* Config setters now take `impl Into`. ## v0.7.10 - 2023-08-25 diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index f762b1184..c2f80dc7e 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tokio-postgres" -version = "0.7.10" +version = "0.7.11" authors = ["Steven Fackler "] edition = "2018" license = "MIT OR Apache-2.0" From 9f196e7f5ba6067efe55f758d743cdfd9b606cff Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 21 Jul 2024 20:38:52 -0400 Subject: [PATCH 358/420] Release postgres v0.19.8 --- postgres-native-tls/Cargo.toml | 2 +- postgres-openssl/Cargo.toml | 2 +- postgres/CHANGELOG.md | 6 ++++++ postgres/Cargo.toml | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/postgres-native-tls/Cargo.toml b/postgres-native-tls/Cargo.toml index 6c17d0889..02259b3dc 100644 --- a/postgres-native-tls/Cargo.toml +++ b/postgres-native-tls/Cargo.toml @@ -24,4 +24,4 @@ tokio-postgres = { version = "0.7.11", path = "../tokio-postgres", default-featu [dev-dependencies] futures-util = "0.3" tokio = { version = "1.0", features = ["macros", "net", "rt"] } -postgres = { version = "0.19.0", path = "../postgres" } +postgres = { version = "0.19.8", path = "../postgres" } diff --git a/postgres-openssl/Cargo.toml b/postgres-openssl/Cargo.toml index 7c19070bf..9013384a2 100644 --- a/postgres-openssl/Cargo.toml +++ b/postgres-openssl/Cargo.toml @@ -24,4 +24,4 @@ tokio-postgres = { version = "0.7.11", path = "../tokio-postgres", default-featu [dev-dependencies] futures-util = "0.3" tokio = { version = "1.0", features = ["macros", "net", "rt"] } -postgres = { version = "0.19.0", path = "../postgres" } +postgres = { version = "0.19.8", path = "../postgres" } diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index 7f856b5ac..258cdb518 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## v0.19.8 - 2024-07-21 + +### Added + +* Added `{Client, Transaction, GenericClient}::query_typed`. + ## v0.19.7 - 2023-08-25 ## Fixed diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index f1dc3c685..ff95c4f14 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "postgres" -version = "0.19.7" +version = "0.19.8" authors = ["Steven Fackler "] edition = "2018" license = "MIT OR Apache-2.0" From 6de0fceebe3c1800a5e812f35449e464fbc33f55 Mon Sep 17 00:00:00 2001 From: Allan Zhang Date: Mon, 22 Jul 2024 15:54:40 -0400 Subject: [PATCH 359/420] Add jiff support --- postgres-types/CHANGELOG.md | 4 ++ postgres-types/Cargo.toml | 2 + postgres-types/src/jiff_01.rs | 118 ++++++++++++++++++++++++++++++++++ postgres-types/src/lib.rs | 7 ++ postgres/CHANGELOG.md | 6 ++ postgres/Cargo.toml | 1 + tokio-postgres/CHANGELOG.md | 4 ++ tokio-postgres/Cargo.toml | 2 + tokio-postgres/src/lib.rs | 1 + 9 files changed, 145 insertions(+) create mode 100644 postgres-types/src/jiff_01.rs diff --git a/postgres-types/CHANGELOG.md b/postgres-types/CHANGELOG.md index 1e5cd31d8..b11e18d32 100644 --- a/postgres-types/CHANGELOG.md +++ b/postgres-types/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Added + +* Added support for `jiff` 0.1 via the `with-jiff-01` feature. + ## v0.2.7 - 2024-07-21 ### Added diff --git a/postgres-types/Cargo.toml b/postgres-types/Cargo.toml index e2d21b358..941f4fcc4 100644 --- a/postgres-types/Cargo.toml +++ b/postgres-types/Cargo.toml @@ -21,6 +21,7 @@ with-eui48-0_4 = ["eui48-04"] with-eui48-1 = ["eui48-1"] with-geo-types-0_6 = ["geo-types-06"] with-geo-types-0_7 = ["geo-types-0_7"] +with-jiff-0_1 = ["jiff-01"] with-serde_json-1 = ["serde-1", "serde_json-1"] with-smol_str-01 = ["smol_str-01"] with-uuid-0_8 = ["uuid-08"] @@ -46,6 +47,7 @@ eui48-04 = { version = "0.4", package = "eui48", optional = true } eui48-1 = { version = "1.0", package = "eui48", optional = true, default-features = false } geo-types-06 = { version = "0.6", package = "geo-types", optional = true } geo-types-0_7 = { version = "0.7", package = "geo-types", optional = true } +jiff-01 = { version = "0.1", package = "jiff", optional = true } serde-1 = { version = "1.0", package = "serde", optional = true } serde_json-1 = { version = "1.0", package = "serde_json", optional = true } uuid-08 = { version = "0.8", package = "uuid", optional = true } diff --git a/postgres-types/src/jiff_01.rs b/postgres-types/src/jiff_01.rs new file mode 100644 index 000000000..eec6aa2f8 --- /dev/null +++ b/postgres-types/src/jiff_01.rs @@ -0,0 +1,118 @@ +use bytes::BytesMut; +use jiff_01::{ + civil::{Date, DateTime, Time}, + tz::TimeZone, + Span, Timestamp as JiffTimestamp, Zoned, +}; +use postgres_protocol::types; +use std::error::Error; + +use crate::{FromSql, IsNull, ToSql, Type}; + +const fn base() -> DateTime { + DateTime::constant(2000, 1, 1, 0, 0, 0, 0) +} + +impl<'a> FromSql<'a> for DateTime { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let t = types::timestamp_from_sql(raw)?; + Ok(base().checked_add(Span::new().microseconds(t))?) + } + + accepts!(TIMESTAMP); +} + +impl ToSql for DateTime { + fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { + types::timestamp_to_sql(self.since(base())?.get_microseconds(), w); + Ok(IsNull::No) + } + + accepts!(TIMESTAMP); + to_sql_checked!(); +} + +impl<'a> FromSql<'a> for JiffTimestamp { + fn from_sql(type_: &Type, raw: &[u8]) -> Result> { + Ok(DateTime::from_sql(type_, raw)? + .to_zoned(TimeZone::UTC)? + .timestamp()) + } + + accepts!(TIMESTAMPTZ); +} + +impl ToSql for JiffTimestamp { + fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { + types::timestamp_to_sql( + self.since(base().to_zoned(TimeZone::UTC)?)? + .get_microseconds(), + w, + ); + Ok(IsNull::No) + } + + accepts!(TIMESTAMPTZ); + to_sql_checked!(); +} + +impl<'a> FromSql<'a> for Zoned { + fn from_sql(type_: &Type, raw: &[u8]) -> Result> { + Ok(JiffTimestamp::from_sql(type_, raw)?.to_zoned(TimeZone::UTC)) + } + + accepts!(TIMESTAMPTZ); +} + +impl ToSql for Zoned { + fn to_sql( + &self, + type_: &Type, + w: &mut BytesMut, + ) -> Result> { + self.timestamp().to_sql(type_, w) + } + + accepts!(TIMESTAMPTZ); + to_sql_checked!(); +} + +impl<'a> FromSql<'a> for Date { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let jd = types::date_from_sql(raw)?; + Ok(base().date().checked_add(Span::new().days(jd))?) + } + + accepts!(DATE); +} + +impl ToSql for Date { + fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { + let jd = self.since(base().date())?.get_days(); + types::date_to_sql(jd, w); + Ok(IsNull::No) + } + + accepts!(DATE); + to_sql_checked!(); +} + +impl<'a> FromSql<'a> for Time { + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let usec = types::time_from_sql(raw)?; + Ok(Time::midnight() + Span::new().microseconds(usec)) + } + + accepts!(TIME); +} + +impl ToSql for Time { + fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { + let delta = self.since(Time::midnight())?; + types::time_to_sql(delta.get_microseconds(), w); + Ok(IsNull::No) + } + + accepts!(TIME); + to_sql_checked!(); +} diff --git a/postgres-types/src/lib.rs b/postgres-types/src/lib.rs index 492039766..7d6d976c6 100644 --- a/postgres-types/src/lib.rs +++ b/postgres-types/src/lib.rs @@ -276,6 +276,8 @@ mod eui48_1; mod geo_types_06; #[cfg(feature = "with-geo-types-0_7")] mod geo_types_07; +#[cfg(feature = "with-jiff-0_1")] +mod jiff_01; #[cfg(feature = "with-serde_json-1")] mod serde_json_1; #[cfg(feature = "with-smol_str-01")] @@ -491,6 +493,11 @@ impl WrongType { /// | `time::OffsetDateTime` | TIMESTAMP WITH TIME ZONE | /// | `time::Date` | DATE | /// | `time::Time` | TIME | +/// | `jiff::civil::DateTime` | TIMESTAMP | +/// | `jiff::Timestamp` | TIMESTAMP WITH TIME ZONE | +/// | `jiff::Zoned` | TIMESTAMP WITH TIME ZONE | +/// | `jiff::civil::Date` | DATE | +/// | `jiff::civil::Time` | TIME | /// | `eui48::MacAddress` | MACADDR | /// | `geo_types::Point` | POINT | /// | `geo_types::Rect` | BOX | diff --git a/postgres/CHANGELOG.md b/postgres/CHANGELOG.md index 258cdb518..6feb629e4 100644 --- a/postgres/CHANGELOG.md +++ b/postgres/CHANGELOG.md @@ -1,5 +1,11 @@ # Change Log +## Unreleased + +### Added + +* Added support for `jiff` 0.1 via the `with-jiff-01` feature. + ## v0.19.8 - 2024-07-21 ### Added diff --git a/postgres/Cargo.toml b/postgres/Cargo.toml index ff95c4f14..e0e580f7d 100644 --- a/postgres/Cargo.toml +++ b/postgres/Cargo.toml @@ -28,6 +28,7 @@ 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"] with-geo-types-0_7 = ["tokio-postgres/with-geo-types-0_7"] +with-jiff-0_1 = ["tokio-postgres/with-jiff-0_1"] with-serde_json-1 = ["tokio-postgres/with-serde_json-1"] with-smol_str-01 = ["tokio-postgres/with-smol_str-01"] with-uuid-0_8 = ["tokio-postgres/with-uuid-0_8"] diff --git a/tokio-postgres/CHANGELOG.md b/tokio-postgres/CHANGELOG.md index e0be26296..bf17ec486 100644 --- a/tokio-postgres/CHANGELOG.md +++ b/tokio-postgres/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Added + +* Added support for `jiff` 0.1 via the `with-jiff-01` feature. + ## v0.7.11 - 2024-07-21 ### Fixed diff --git a/tokio-postgres/Cargo.toml b/tokio-postgres/Cargo.toml index c2f80dc7e..e1e84f7b1 100644 --- a/tokio-postgres/Cargo.toml +++ b/tokio-postgres/Cargo.toml @@ -34,6 +34,7 @@ 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"] with-geo-types-0_7 = ["postgres-types/with-geo-types-0_7"] +with-jiff-0_1 = ["postgres-types/with-jiff-0_1"] with-serde_json-1 = ["postgres-types/with-serde_json-1"] with-smol_str-01 = ["postgres-types/with-smol_str-01"] with-uuid-0_8 = ["postgres-types/with-uuid-0_8"] @@ -81,6 +82,7 @@ chrono-04 = { version = "0.4", package = "chrono", default-features = false } eui48-1 = { version = "1.0", package = "eui48", default-features = false } geo-types-06 = { version = "0.6", package = "geo-types" } geo-types-07 = { version = "0.7", package = "geo-types" } +jiff-01 = { version = "0.1", package = "jiff" } serde-1 = { version = "1.0", package = "serde" } serde_json-1 = { version = "1.0", package = "serde_json" } smol_str-01 = { version = "0.1", package = "smol_str" } diff --git a/tokio-postgres/src/lib.rs b/tokio-postgres/src/lib.rs index a603158fb..ec843d511 100644 --- a/tokio-postgres/src/lib.rs +++ b/tokio-postgres/src/lib.rs @@ -111,6 +111,7 @@ //! | `with-eui48-1` | Enable support for the 1.0 version of the `eui48` crate. | [eui48](https://crates.io/crates/eui48) 1.0 | no | //! | `with-geo-types-0_6` | Enable support for the 0.6 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.6.0) 0.6 | no | //! | `with-geo-types-0_7` | Enable support for the 0.7 version of the `geo-types` crate. | [geo-types](https://crates.io/crates/geo-types/0.7.0) 0.7 | no | +//! | `with-jiff-0_1` | Enable support for the 0.1 version of the `jiff` crate. | [jiff](https://crates.io/crates/jiff/0.1.0) 0.1 | no | //! | `with-serde_json-1` | Enable support for the `serde_json` crate. | [serde_json](https://crates.io/crates/serde_json) 1.0 | no | //! | `with-uuid-0_8` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 0.8 | no | //! | `with-uuid-1` | Enable support for the `uuid` crate. | [uuid](https://crates.io/crates/uuid) 1.0 | no | From 0fc4005ed31e3705a04cb7e58eb220d89b922dd0 Mon Sep 17 00:00:00 2001 From: Ramnivas Laddad Date: Mon, 22 Jul 2024 15:07:44 -0700 Subject: [PATCH 360/420] For `query_typed`, deal with the no-data case. If a query returns no data, we receive `Message::NoData`, which signals the completion of the query. However, we treated it as a no-op, leading to processing other messages and eventual failure. This PR fixes the issue and updates the `query_typed` tests to cover this scenario. --- tokio-postgres/src/query.rs | 13 +++++++++---- tokio-postgres/tests/test/main.rs | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/tokio-postgres/src/query.rs b/tokio-postgres/src/query.rs index be42d66b6..3ab002871 100644 --- a/tokio-postgres/src/query.rs +++ b/tokio-postgres/src/query.rs @@ -89,10 +89,15 @@ where loop { match responses.next().await? { - Message::ParseComplete - | Message::BindComplete - | Message::ParameterDescription(_) - | Message::NoData => {} + Message::ParseComplete | Message::BindComplete | Message::ParameterDescription(_) => {} + Message::NoData => { + return Ok(RowStream { + statement: Statement::unnamed(vec![], vec![]), + responses, + rows_affected: None, + _p: PhantomPinned, + }); + } Message::RowDescription(row_description) => { let mut columns: Vec = vec![]; let mut it = row_description.fields(); diff --git a/tokio-postgres/tests/test/main.rs b/tokio-postgres/tests/test/main.rs index 84c46d101..9a6aa26fe 100644 --- a/tokio-postgres/tests/test/main.rs +++ b/tokio-postgres/tests/test/main.rs @@ -997,6 +997,13 @@ async fn query_typed_no_transaction() { assert_eq!(second_row.get::<_, i32>(1), 40); assert_eq!(second_row.get::<_, &str>(2), "literal"); assert_eq!(second_row.get::<_, i32>(3), 5); + + // Test for UPDATE that returns no data + let updated_rows = client + .query_typed("UPDATE foo set age = 33", &[]) + .await + .unwrap(); + assert_eq!(updated_rows.len(), 0); } #[tokio::test] @@ -1064,4 +1071,11 @@ async fn query_typed_with_transaction() { assert_eq!(second_row.get::<_, i32>(1), 40); assert_eq!(second_row.get::<_, &str>(2), "literal"); assert_eq!(second_row.get::<_, i32>(3), 5); + + // Test for UPDATE that returns no data + let updated_rows = transaction + .query_typed("UPDATE foo set age = 33", &[]) + .await + .unwrap(); + assert_eq!(updated_rows.len(), 0); } From aa10f0d75cb23757c9a87fe58363e4e26ae19d1e Mon Sep 17 00:00:00 2001 From: Qiu Chaofan Date: Tue, 23 Jul 2024 13:36:51 +0800 Subject: [PATCH 361/420] Support AIX keepalive --- tokio-postgres/src/keepalive.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tokio-postgres/src/keepalive.rs b/tokio-postgres/src/keepalive.rs index c409eb0ea..7bdd76341 100644 --- a/tokio-postgres/src/keepalive.rs +++ b/tokio-postgres/src/keepalive.rs @@ -12,12 +12,18 @@ impl From<&KeepaliveConfig> for TcpKeepalive { fn from(keepalive_config: &KeepaliveConfig) -> Self { let mut tcp_keepalive = Self::new().with_time(keepalive_config.idle); - #[cfg(not(any(target_os = "redox", target_os = "solaris", target_os = "openbsd")))] + #[cfg(not(any( + target_os = "aix", + target_os = "redox", + target_os = "solaris", + target_os = "openbsd" + )))] if let Some(interval) = keepalive_config.interval { tcp_keepalive = tcp_keepalive.with_interval(interval); } #[cfg(not(any( + target_os = "aix", target_os = "redox", target_os = "solaris", target_os = "windows", From df2f37d848f5779ed1dc6c1a8f8ded32a15e70c3 Mon Sep 17 00:00:00 2001 From: Allan Zhang Date: Tue, 23 Jul 2024 07:54:19 -0400 Subject: [PATCH 362/420] Remove unecessary alias for Timestamp --- postgres-types/src/jiff_01.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/postgres-types/src/jiff_01.rs b/postgres-types/src/jiff_01.rs index eec6aa2f8..c2e4ef06e 100644 --- a/postgres-types/src/jiff_01.rs +++ b/postgres-types/src/jiff_01.rs @@ -2,7 +2,7 @@ use bytes::BytesMut; use jiff_01::{ civil::{Date, DateTime, Time}, tz::TimeZone, - Span, Timestamp as JiffTimestamp, Zoned, + Span, Timestamp, Zoned, }; use postgres_protocol::types; use std::error::Error; @@ -32,8 +32,8 @@ impl ToSql for DateTime { to_sql_checked!(); } -impl<'a> FromSql<'a> for JiffTimestamp { - fn from_sql(type_: &Type, raw: &[u8]) -> Result> { +impl<'a> FromSql<'a> for Timestamp { + fn from_sql(type_: &Type, raw: &[u8]) -> Result> { Ok(DateTime::from_sql(type_, raw)? .to_zoned(TimeZone::UTC)? .timestamp()) @@ -42,7 +42,7 @@ impl<'a> FromSql<'a> for JiffTimestamp { accepts!(TIMESTAMPTZ); } -impl ToSql for JiffTimestamp { +impl ToSql for Timestamp { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { types::timestamp_to_sql( self.since(base().to_zoned(TimeZone::UTC)?)? @@ -58,7 +58,7 @@ impl ToSql for JiffTimestamp { impl<'a> FromSql<'a> for Zoned { fn from_sql(type_: &Type, raw: &[u8]) -> Result> { - Ok(JiffTimestamp::from_sql(type_, raw)?.to_zoned(TimeZone::UTC)) + Ok(Timestamp::from_sql(type_, raw)?.to_zoned(TimeZone::UTC)) } accepts!(TIMESTAMPTZ); From f00d208959c8c76c9bbe943f53a9a261ef1d2315 Mon Sep 17 00:00:00 2001 From: Allan Zhang Date: Tue, 23 Jul 2024 07:56:00 -0400 Subject: [PATCH 363/420] Update impl for Timestamp The impl now directly computes `Timestamp` rather than going through `DateTime` and `Zoned`. --- postgres-types/src/jiff_01.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/postgres-types/src/jiff_01.rs b/postgres-types/src/jiff_01.rs index c2e4ef06e..d8f8723b6 100644 --- a/postgres-types/src/jiff_01.rs +++ b/postgres-types/src/jiff_01.rs @@ -13,6 +13,13 @@ const fn base() -> DateTime { DateTime::constant(2000, 1, 1, 0, 0, 0, 0) } +/// The number of seconds from 2000-01-01 00:00:00 UTC to the Unix epoch. +const Y2K_EPOCH: i64 = 946684800; + +fn base_ts() -> Timestamp { + Timestamp::new(Y2K_EPOCH, 0).unwrap() +} + impl<'a> FromSql<'a> for DateTime { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let t = types::timestamp_from_sql(raw)?; @@ -33,10 +40,9 @@ impl ToSql for DateTime { } impl<'a> FromSql<'a> for Timestamp { - fn from_sql(type_: &Type, raw: &[u8]) -> Result> { - Ok(DateTime::from_sql(type_, raw)? - .to_zoned(TimeZone::UTC)? - .timestamp()) + fn from_sql(_: &Type, raw: &[u8]) -> Result> { + let t = types::timestamp_from_sql(raw)?; + Ok(base_ts().checked_add(Span::new().microseconds(t))?) } accepts!(TIMESTAMPTZ); @@ -44,11 +50,7 @@ impl<'a> FromSql<'a> for Timestamp { impl ToSql for Timestamp { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { - types::timestamp_to_sql( - self.since(base().to_zoned(TimeZone::UTC)?)? - .get_microseconds(), - w, - ); + types::timestamp_to_sql(self.since(base_ts())?.get_microseconds(), w); Ok(IsNull::No) } From 815a5d3ae9a580dcc6db3312c8945417eac680f2 Mon Sep 17 00:00:00 2001 From: Allan Zhang Date: Tue, 23 Jul 2024 07:58:47 -0400 Subject: [PATCH 364/420] Remove impl for `Zoned` `Timestamp` already has impl and is semantically accurate for mapping to `timestamptz`, unlike `Zoned`. End users can do their own conversions from `Timestamp` to `Zoned` if desired. --- postgres-types/src/jiff_01.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/postgres-types/src/jiff_01.rs b/postgres-types/src/jiff_01.rs index d8f8723b6..8a0a38f7c 100644 --- a/postgres-types/src/jiff_01.rs +++ b/postgres-types/src/jiff_01.rs @@ -58,27 +58,6 @@ impl ToSql for Timestamp { to_sql_checked!(); } -impl<'a> FromSql<'a> for Zoned { - fn from_sql(type_: &Type, raw: &[u8]) -> Result> { - Ok(Timestamp::from_sql(type_, raw)?.to_zoned(TimeZone::UTC)) - } - - accepts!(TIMESTAMPTZ); -} - -impl ToSql for Zoned { - fn to_sql( - &self, - type_: &Type, - w: &mut BytesMut, - ) -> Result> { - self.timestamp().to_sql(type_, w) - } - - accepts!(TIMESTAMPTZ); - to_sql_checked!(); -} - impl<'a> FromSql<'a> for Date { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let jd = types::date_from_sql(raw)?; From e19b3dc164ba0cc4f1e601149dc7e7b2837e7276 Mon Sep 17 00:00:00 2001 From: Allan Zhang Date: Wed, 14 Aug 2024 09:00:42 -0400 Subject: [PATCH 365/420] Rename PG_EPOCH --- postgres-types/src/jiff_01.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/postgres-types/src/jiff_01.rs b/postgres-types/src/jiff_01.rs index 8a0a38f7c..871d35f62 100644 --- a/postgres-types/src/jiff_01.rs +++ b/postgres-types/src/jiff_01.rs @@ -1,8 +1,7 @@ use bytes::BytesMut; use jiff_01::{ civil::{Date, DateTime, Time}, - tz::TimeZone, - Span, Timestamp, Zoned, + Span, Timestamp, }; use postgres_protocol::types; use std::error::Error; @@ -13,11 +12,11 @@ const fn base() -> DateTime { DateTime::constant(2000, 1, 1, 0, 0, 0, 0) } -/// The number of seconds from 2000-01-01 00:00:00 UTC to the Unix epoch. -const Y2K_EPOCH: i64 = 946684800; +/// The number of seconds from the Unix epoch to 2000-01-01 00:00:00 UTC. +const PG_EPOCH: i64 = 946684800; fn base_ts() -> Timestamp { - Timestamp::new(Y2K_EPOCH, 0).unwrap() + Timestamp::new(PG_EPOCH, 0).unwrap() } impl<'a> FromSql<'a> for DateTime { From c96342d7f6e1b86db752e96482ad372024062fab Mon Sep 17 00:00:00 2001 From: Allan Zhang Date: Wed, 14 Aug 2024 09:14:41 -0400 Subject: [PATCH 366/420] Fix ToSql This sets the smallest unit to microseconds when calculating time deltas. Previously, the number of microseconds was expressed improperly because the rounding was not set. --- postgres-types/src/jiff_01.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/postgres-types/src/jiff_01.rs b/postgres-types/src/jiff_01.rs index 871d35f62..54768c10d 100644 --- a/postgres-types/src/jiff_01.rs +++ b/postgres-types/src/jiff_01.rs @@ -1,7 +1,7 @@ use bytes::BytesMut; use jiff_01::{ civil::{Date, DateTime, Time}, - Span, Timestamp, + Span, SpanRound, Timestamp, Unit, }; use postgres_protocol::types; use std::error::Error; @@ -12,13 +12,17 @@ const fn base() -> DateTime { DateTime::constant(2000, 1, 1, 0, 0, 0, 0) } -/// The number of seconds from the Unix epoch to 2000-01-01 00:00:00 UTC. +/// The number of seconds from the Unix epoch to 2000-01-01 00:00:00 UTC. const PG_EPOCH: i64 = 946684800; fn base_ts() -> Timestamp { Timestamp::new(PG_EPOCH, 0).unwrap() } +fn round_us<'a>() -> SpanRound<'a> { + SpanRound::new().largest(Unit::Microsecond) +} + impl<'a> FromSql<'a> for DateTime { fn from_sql(_: &Type, raw: &[u8]) -> Result> { let t = types::timestamp_from_sql(raw)?; @@ -30,7 +34,8 @@ impl<'a> FromSql<'a> for DateTime { impl ToSql for DateTime { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { - types::timestamp_to_sql(self.since(base())?.get_microseconds(), w); + let span = self.since(base())?.round(round_us())?; + types::timestamp_to_sql(span.get_microseconds(), w); Ok(IsNull::No) } @@ -49,7 +54,8 @@ impl<'a> FromSql<'a> for Timestamp { impl ToSql for Timestamp { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { - types::timestamp_to_sql(self.since(base_ts())?.get_microseconds(), w); + let span = self.since(base_ts())?.round(round_us())?; + types::timestamp_to_sql(span.get_microseconds(), w); Ok(IsNull::No) } @@ -88,8 +94,8 @@ impl<'a> FromSql<'a> for Time { impl ToSql for Time { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { - let delta = self.since(Time::midnight())?; - types::time_to_sql(delta.get_microseconds(), w); + let span = self.since(Time::midnight())?.round(round_us())?; + types::time_to_sql(span.get_microseconds(), w); Ok(IsNull::No) } From afef88efb6a2555cf0bed88bd93d5e48f42bffe9 Mon Sep 17 00:00:00 2001 From: Allan Zhang Date: Wed, 14 Aug 2024 20:39:55 -0400 Subject: [PATCH 367/420] Add jiff tests and overflow checks This adds tests in the same fashion as the existing ones for `chrono` and `time`. Overflow is now handled using fallible operations. For example, `Span:microseconds` is replaced with `Span::try_microseconds`. Postgres infinity values are workiing as expected. All tests are passing. --- postgres-types/src/jiff_01.rs | 71 +++++++-- tokio-postgres/tests/test/types/jiff_01.rs | 175 +++++++++++++++++++++ tokio-postgres/tests/test/types/mod.rs | 2 + 3 files changed, 231 insertions(+), 17 deletions(-) create mode 100644 tokio-postgres/tests/test/types/jiff_01.rs diff --git a/postgres-types/src/jiff_01.rs b/postgres-types/src/jiff_01.rs index 54768c10d..d3215c0e6 100644 --- a/postgres-types/src/jiff_01.rs +++ b/postgres-types/src/jiff_01.rs @@ -23,10 +23,27 @@ fn round_us<'a>() -> SpanRound<'a> { SpanRound::new().largest(Unit::Microsecond) } +fn decode_err(_e: E) -> Box +where + E: Error, +{ + "value too large to decode".into() +} + +fn transmit_err(_e: E) -> Box +where + E: Error, +{ + "value too large to transmit".into() +} + impl<'a> FromSql<'a> for DateTime { fn from_sql(_: &Type, raw: &[u8]) -> Result> { - let t = types::timestamp_from_sql(raw)?; - Ok(base().checked_add(Span::new().microseconds(t))?) + let v = types::timestamp_from_sql(raw)?; + Span::new() + .try_microseconds(v) + .and_then(|s| base().checked_add(s)) + .map_err(decode_err) } accepts!(TIMESTAMP); @@ -34,8 +51,12 @@ impl<'a> FromSql<'a> for DateTime { impl ToSql for DateTime { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { - let span = self.since(base())?.round(round_us())?; - types::timestamp_to_sql(span.get_microseconds(), w); + let v = self + .since(base()) + .and_then(|s| s.round(round_us())) + .map_err(transmit_err)? + .get_microseconds(); + types::timestamp_to_sql(v, w); Ok(IsNull::No) } @@ -45,8 +66,11 @@ impl ToSql for DateTime { impl<'a> FromSql<'a> for Timestamp { fn from_sql(_: &Type, raw: &[u8]) -> Result> { - let t = types::timestamp_from_sql(raw)?; - Ok(base_ts().checked_add(Span::new().microseconds(t))?) + let v = types::timestamp_from_sql(raw)?; + Span::new() + .try_microseconds(v) + .and_then(|s| base_ts().checked_add(s)) + .map_err(decode_err) } accepts!(TIMESTAMPTZ); @@ -54,8 +78,12 @@ impl<'a> FromSql<'a> for Timestamp { impl ToSql for Timestamp { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { - let span = self.since(base_ts())?.round(round_us())?; - types::timestamp_to_sql(span.get_microseconds(), w); + let v = self + .since(base_ts()) + .and_then(|s| s.round(round_us())) + .map_err(transmit_err)? + .get_microseconds(); + types::timestamp_to_sql(v, w); Ok(IsNull::No) } @@ -65,17 +93,19 @@ impl ToSql for Timestamp { impl<'a> FromSql<'a> for Date { fn from_sql(_: &Type, raw: &[u8]) -> Result> { - let jd = types::date_from_sql(raw)?; - Ok(base().date().checked_add(Span::new().days(jd))?) + let v = types::date_from_sql(raw)?; + Span::new() + .try_days(v) + .and_then(|s| base().date().checked_add(s)) + .map_err(decode_err) } - accepts!(DATE); } impl ToSql for Date { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { - let jd = self.since(base().date())?.get_days(); - types::date_to_sql(jd, w); + let v = self.since(base().date()).map_err(transmit_err)?.get_days(); + types::date_to_sql(v, w); Ok(IsNull::No) } @@ -85,8 +115,11 @@ impl ToSql for Date { impl<'a> FromSql<'a> for Time { fn from_sql(_: &Type, raw: &[u8]) -> Result> { - let usec = types::time_from_sql(raw)?; - Ok(Time::midnight() + Span::new().microseconds(usec)) + let v = types::time_from_sql(raw)?; + Span::new() + .try_microseconds(v) + .and_then(|s| Time::midnight().checked_add(s)) + .map_err(decode_err) } accepts!(TIME); @@ -94,8 +127,12 @@ impl<'a> FromSql<'a> for Time { impl ToSql for Time { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { - let span = self.since(Time::midnight())?.round(round_us())?; - types::time_to_sql(span.get_microseconds(), w); + let v = self + .since(Time::midnight()) + .and_then(|s| s.round(round_us())) + .map_err(transmit_err)? + .get_microseconds(); + types::time_to_sql(v, w); Ok(IsNull::No) } diff --git a/tokio-postgres/tests/test/types/jiff_01.rs b/tokio-postgres/tests/test/types/jiff_01.rs new file mode 100644 index 000000000..7c9052676 --- /dev/null +++ b/tokio-postgres/tests/test/types/jiff_01.rs @@ -0,0 +1,175 @@ +use jiff_01::{ + civil::{Date as JiffDate, DateTime, Time}, + Timestamp as JiffTimestamp, +}; +use std::fmt; +use tokio_postgres::{ + types::{Date, FromSqlOwned, Timestamp}, + Client, +}; + +use crate::connect; +use crate::types::test_type; + +#[tokio::test] +async fn test_datetime_params() { + fn make_check(s: &str) -> (Option, &str) { + (Some(s.trim_matches('\'').parse().unwrap()), s) + } + test_type( + "TIMESTAMP", + &[ + make_check("'1970-01-01 00:00:00.010000000'"), + make_check("'1965-09-25 11:19:33.100314000'"), + make_check("'2010-02-09 23:11:45.120200000'"), + (None, "NULL"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_with_special_datetime_params() { + fn make_check(s: &str) -> (Timestamp, &str) { + (Timestamp::Value(s.trim_matches('\'').parse().unwrap()), s) + } + test_type( + "TIMESTAMP", + &[ + make_check("'1970-01-01 00:00:00.010000000'"), + make_check("'1965-09-25 11:19:33.100314000'"), + make_check("'2010-02-09 23:11:45.120200000'"), + (Timestamp::PosInfinity, "'infinity'"), + (Timestamp::NegInfinity, "'-infinity'"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_timestamp_params() { + fn make_check(s: &str) -> (Option, &str) { + (Some(s.trim_matches('\'').parse().unwrap()), s) + } + test_type( + "TIMESTAMP WITH TIME ZONE", + &[ + make_check("'1970-01-01 00:00:00.010000000Z'"), + make_check("'1965-09-25 11:19:33.100314000Z'"), + make_check("'2010-02-09 23:11:45.120200000Z'"), + (None, "NULL"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_with_special_timestamp_params() { + fn make_check(s: &str) -> (Timestamp, &str) { + (Timestamp::Value(s.trim_matches('\'').parse().unwrap()), s) + } + test_type( + "TIMESTAMP WITH TIME ZONE", + &[ + make_check("'1970-01-01 00:00:00.010000000Z'"), + make_check("'1965-09-25 11:19:33.100314000Z'"), + make_check("'2010-02-09 23:11:45.120200000Z'"), + (Timestamp::PosInfinity, "'infinity'"), + (Timestamp::NegInfinity, "'-infinity'"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_date_params() { + fn make_check(s: &str) -> (Option, &str) { + (Some(s.trim_matches('\'').parse().unwrap()), s) + } + test_type( + "DATE", + &[ + make_check("'1970-01-01'"), + make_check("'1965-09-25'"), + make_check("'2010-02-09'"), + (None, "NULL"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_with_special_date_params() { + fn make_check(s: &str) -> (Date, &str) { + (Date::Value(s.trim_matches('\'').parse().unwrap()), s) + } + test_type( + "DATE", + &[ + make_check("'1970-01-01'"), + make_check("'1965-09-25'"), + make_check("'2010-02-09'"), + (Date::PosInfinity, "'infinity'"), + (Date::NegInfinity, "'-infinity'"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_time_params() { + fn make_check(s: &str) -> (Option