From 0fc4005ed31e3705a04cb7e58eb220d89b922dd0 Mon Sep 17 00:00:00 2001 From: Ramnivas Laddad Date: Mon, 22 Jul 2024 15:07:44 -0700 Subject: [PATCH 1/6] 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 2/6] 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 672140b941daa44750ab66b6d23880e344e1a2b0 Mon Sep 17 00:00:00 2001 From: Mark Hendrickson Date: Fri, 2 Aug 2024 17:16:34 -0400 Subject: [PATCH 3/6] removed unused deps --- postgres-types/src/jiff_01.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/postgres-types/src/jiff_01.rs b/postgres-types/src/jiff_01.rs index 8a0a38f7c..2e75353e6 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; From 74a619255b8c3e96cae805112314c185d2b752a8 Mon Sep 17 00:00:00 2001 From: Mark Hendrickson Date: Fri, 2 Aug 2024 17:51:07 -0400 Subject: [PATCH 4/6] added mod for jiff_01 behind feature flag with-jiff-0_1 --- tokio-postgres/tests/test/types/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tokio-postgres/tests/test/types/mod.rs b/tokio-postgres/tests/test/types/mod.rs index 62d54372a..f962bf10a 100644 --- a/tokio-postgres/tests/test/types/mod.rs +++ b/tokio-postgres/tests/test/types/mod.rs @@ -23,6 +23,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")] From 8e249e05a9aa10b94b458dd298c6b4dd53776d3b Mon Sep 17 00:00:00 2001 From: Mark Hendrickson Date: Fri, 2 Aug 2024 19:49:10 -0400 Subject: [PATCH 5/6] fixed getting total microseconds, use try_microseconds to create span --- postgres-types/src/jiff_01.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/postgres-types/src/jiff_01.rs b/postgres-types/src/jiff_01.rs index 2e75353e6..9566694d6 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, Timestamp, Unit, }; use postgres_protocol::types; use std::error::Error; @@ -22,7 +22,7 @@ fn base_ts() -> Timestamp { 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))?) + Ok(base().checked_add(Span::new().try_microseconds(t)?)?) } accepts!(TIMESTAMP); @@ -30,7 +30,7 @@ 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); + types::timestamp_to_sql(self.since(base())?.total(Unit::Microsecond)? as i64, w); Ok(IsNull::No) } @@ -41,7 +41,7 @@ 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))?) + Ok(base_ts().checked_add(Span::new().try_microseconds(t)?)?) } accepts!(TIMESTAMPTZ); @@ -49,7 +49,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_ts())?.get_microseconds(), w); + types::timestamp_to_sql(self.since(base_ts())?.total(Unit::Microsecond)? as i64, w); Ok(IsNull::No) } @@ -60,7 +60,7 @@ 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))?) + Ok(base().date().checked_add(Span::new().try_days(jd)?)?) } accepts!(DATE); @@ -68,7 +68,7 @@ impl<'a> FromSql<'a> for Date { impl ToSql for Date { fn to_sql(&self, _: &Type, w: &mut BytesMut) -> Result> { - let jd = self.since(base().date())?.get_days(); + let jd = self.since(base())?.total(Unit::Day)? as i32; types::date_to_sql(jd, w); Ok(IsNull::No) } @@ -80,7 +80,7 @@ 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)) + Ok(Time::midnight() + Span::new().try_microseconds(usec)?) } accepts!(TIME); @@ -89,7 +89,7 @@ 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); + types::time_to_sql(delta.total(Unit::Microsecond)? as i64, w); Ok(IsNull::No) } From 2f3f12659bf462047b53d6157e4239de635f57c3 Mon Sep 17 00:00:00 2001 From: Mark Hendrickson Date: Fri, 2 Aug 2024 19:49:15 -0400 Subject: [PATCH 6/6] added tests --- tokio-postgres/tests/test/types/jiff_01.rs | 176 +++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 tokio-postgres/tests/test/types/jiff_01.rs 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..524f47010 --- /dev/null +++ b/tokio-postgres/tests/test/types/jiff_01.rs @@ -0,0 +1,176 @@ +use jiff_01::{civil::Date, civil::DateTime, civil::Time, Timestamp}; +use std::fmt; +use tokio_postgres::types::{self, FromSqlOwned}; +use tokio_postgres::Client; + +use crate::connect; +use crate::types::test_type; + +#[tokio::test] +async fn test_civil_datetime_params() { + fn make_check(time: &str) -> (Option, &str) { + ( + Some(DateTime::strptime("'%Y-%m-%d %H:%M:%S.%f'", time).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_civil_datetime_params() { + fn make_check(time: &str) -> (types::Timestamp, &str) { + ( + types::Timestamp::Value(DateTime::strptime("'%Y-%m-%d %H:%M:%S.%f'", time).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'"), + (types::Timestamp::PosInfinity, "'infinity'"), + (types::Timestamp::NegInfinity, "'-infinity'"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_timestamp_params() { + fn make_check(time: &str) -> (Option, &str) { + ( + Some(Timestamp::strptime("'%Y-%m-%d %H:%M:%S.%f %z'", time).unwrap()), + time, + ) + } + test_type( + "TIMESTAMP WITH TIME ZONE", + &[ + make_check("'1970-01-01 00:00:00.010000000 +0000'"), + make_check("'1965-09-25 11:19:33.100314000 +0000'"), + make_check("'2010-02-09 23:11:45.120200000 +0000'"), + make_check("'2010-11-20 17:11:45.120200000 +0500'"), + (None, "NULL"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_with_special_timestamp_params() { + fn make_check(time: &str) -> (types::Timestamp, &str) { + ( + types::Timestamp::Value( + Timestamp::strptime("'%Y-%m-%d %H:%M:%S.%f %z'", time).unwrap(), + ), + time, + ) + } + test_type( + "TIMESTAMP WITH TIME ZONE", + &[ + make_check("'1970-01-01 00:00:00.010000000 +0000'"), + make_check("'1965-09-25 11:19:33.100314000 +0000'"), + make_check("'2010-02-09 23:11:45.120200000 +0000'"), + (types::Timestamp::PosInfinity, "'infinity'"), + (types::Timestamp::NegInfinity, "'-infinity'"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_date_params() { + fn make_check(time: &str) -> (Option, &str) { + (Some(Date::strptime("'%Y-%m-%d'", time).unwrap()), time) + } + 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) -> (types::Date, &str) { + ( + types::Date::Value(Date::strptime("'%Y-%m-%d'", date).unwrap()), + date, + ) + } + test_type( + "DATE", + &[ + make_check("'1970-01-01'"), + make_check("'1965-09-25'"), + make_check("'2010-02-09'"), + (types::Date::PosInfinity, "'infinity'"), + (types::Date::NegInfinity, "'-infinity'"), + ], + ) + .await; +} + +#[tokio::test] +async fn test_time_params() { + fn make_check(time: &str) -> (Option