diff --git a/Cargo.lock b/Cargo.lock index 2f0ddab8d8..a957317fa9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -265,12 +265,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -[[package]] -name = "base-x" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" - [[package]] name = "base64" version = "0.13.0" @@ -371,7 +365,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" dependencies = [ - "rustc_version 0.4.0", + "rustc_version", ] [[package]] @@ -483,12 +477,6 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" -[[package]] -name = "const_fn" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" - [[package]] name = "core-foundation" version = "0.9.2" @@ -738,12 +726,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "dotenv" version = "0.15.0" @@ -1835,12 +1817,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - [[package]] name = "proc-macro2" version = "1.0.36" @@ -2058,22 +2034,13 @@ dependencies = [ "serde", ] -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver 0.9.0", -] - [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.4", + "semver", ] [[package]] @@ -2172,27 +2139,12 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.132" @@ -2248,12 +2200,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "sha1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" - [[package]] name = "sha2" version = "0.9.8" @@ -2362,7 +2308,7 @@ dependencies = [ "sqlx-macros", "sqlx-rt", "sqlx-test", - "time 0.2.27", + "time 0.3.5", "tokio", "trybuild", "url", @@ -2458,7 +2404,7 @@ dependencies = [ "sqlx-rt", "stringprep", "thiserror", - "time 0.2.27", + "time 0.3.5", "tokio-stream", "url", "uuid", @@ -2584,64 +2530,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "stringprep" version = "0.1.2" @@ -2804,41 +2692,20 @@ dependencies = [ [[package]] name = "time" -version = "0.2.27" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad" dependencies = [ - "const_fn", + "itoa 0.4.8", "libc", - "standback", - "stdweb", "time-macros", - "version_check", - "winapi", ] [[package]] name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - -[[package]] -name = "time-macros-impl" -version = "0.1.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn", -] +checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6" [[package]] name = "tinytemplate" diff --git a/Cargo.toml b/Cargo.toml index 7a2ea8ae28..c0cc789bc6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -137,7 +137,7 @@ sqlx-macros = { version = "0.5.10", path = "sqlx-macros", default-features = fal [dev-dependencies] anyhow = "1.0.52" -time_ = { version = "0.2.27", package = "time" } +time_ = { version = "0.3.2", package = "time" } futures = "0.3.19" env_logger = "0.8.4" async-std = { version = "1.10.0", features = ["attributes"] } diff --git a/sqlx-core/Cargo.toml b/sqlx-core/Cargo.toml index e8912206fa..eee42ae58b 100644 --- a/sqlx-core/Cargo.toml +++ b/sqlx-core/Cargo.toml @@ -151,7 +151,7 @@ sha-1 = { version = "0.9.8", default-features = false, optional = true } sha2 = { version = "0.9.8", default-features = false, optional = true } sqlformat = "0.1.8" thiserror = "1.0.30" -time = { version = "0.2.27", optional = true } +time = { version = "0.3.2", features = ["macros", "formatting", "parsing"], optional = true } tokio-stream = { version = "0.1.8", features = ["fs"], optional = true } smallvec = "1.7.0" url = { version = "2.2.2", default-features = false } diff --git a/sqlx-core/src/mysql/types/time.rs b/sqlx-core/src/mysql/types/time.rs index d3a392ad42..fc600257f5 100644 --- a/sqlx-core/src/mysql/types/time.rs +++ b/sqlx-core/src/mysql/types/time.rs @@ -1,8 +1,8 @@ -use std::borrow::Cow; use std::convert::TryFrom; use byteorder::{ByteOrder, LittleEndian}; use bytes::Buf; +use time::macros::format_description; use time::{Date, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset}; use crate::decode::Decode; @@ -87,7 +87,7 @@ impl<'r> Decode<'r, MySql> for Time { // are 0 then the length is 0 and no further data is send // https://dev.mysql.com/doc/internals/en/binary-protocol-value.html if len == 0 { - return Ok(Time::try_from_hms_micro(0, 0, 0, 0).unwrap()); + return Ok(Time::MIDNIGHT); } // is negative : int<1> @@ -101,21 +101,11 @@ impl<'r> Decode<'r, MySql> for Time { decode_time(len - 5, buf) } - MySqlValueFormat::Text => { - let s = value.as_str()?; - - // If there are less than 9 digits after the decimal point - // We need to zero-pad - // TODO: Ask [time] to add a parse % for less-than-fixed-9 nanos - - let s = if s.len() < 20 { - Cow::Owned(format!("{:0<19}", s)) - } else { - Cow::Borrowed(s) - }; - - Time::parse(&*s, "%H:%M:%S.%N").map_err(Into::into) - } + MySqlValueFormat::Text => Time::parse( + value.as_str()?, + &format_description!("[hour]:[minute]:[second].[subsecond]"), + ) + .map_err(Into::into), } } } @@ -148,7 +138,7 @@ impl<'r> Decode<'r, MySql> for Date { } MySqlValueFormat::Text => { let s = value.as_str()?; - Date::parse(s, "%Y-%m-%d").map_err(Into::into) + Date::parse(s, &format_description!("[year]-[month]-[day]")).map_err(Into::into) } } } @@ -211,21 +201,22 @@ impl<'r> Decode<'r, MySql> for PrimitiveDateTime { MySqlValueFormat::Text => { let s = value.as_str()?; - // If there are less than 9 digits after the decimal point - // We need to zero-pad - // TODO: Ask [time] to add a parse % for less-than-fixed-9 nanos - - let s = if s.len() < 31 { - if s.contains('.') { - Cow::Owned(format!("{:0<30}", s)) - } else { - Cow::Owned(format!("{}.000000000", s)) - } + // If there are no nanoseconds parse without them + if s.contains('.') { + PrimitiveDateTime::parse( + s, + &format_description!( + "[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]" + ), + ) + .map_err(Into::into) } else { - Cow::Borrowed(s) - }; - - PrimitiveDateTime::parse(&*s, "%Y-%m-%d %H:%M:%S.%N").map_err(Into::into) + PrimitiveDateTime::parse( + s, + &format_description!("[year]-[month]-[day] [hour]:[minute]:[second]"), + ) + .map_err(Into::into) + } } } } @@ -237,7 +228,7 @@ fn encode_date(date: &Date, buf: &mut Vec) { .unwrap_or_else(|_| panic!("Date out of range for Mysql: {}", date)); buf.extend_from_slice(&year.to_le_bytes()); - buf.push(date.month()); + buf.push(date.month().into()); buf.push(date.day()); } @@ -247,9 +238,9 @@ fn decode_date(buf: &[u8]) -> Result, BoxDynError> { return Ok(None); } - Date::try_from_ymd( + Date::from_calendar_date( LittleEndian::read_u16(buf) as i32, - buf[2] as u8, + time::Month::try_from(buf[2] as u8)?, buf[3] as u8, ) .map_err(Into::into) @@ -278,6 +269,6 @@ fn decode_time(len: u8, mut buf: &[u8]) -> Result { 0 }; - Time::try_from_hms_micro(hour, minute, seconds, micros as u32) + Time::from_hms_micro(hour, minute, seconds, micros as u32) .map_err(|e| format!("Time out of range for MySQL: {}", e).into()) } diff --git a/sqlx-core/src/postgres/types/time/date.rs b/sqlx-core/src/postgres/types/time/date.rs index 3864826c98..2763d9a1d6 100644 --- a/sqlx-core/src/postgres/types/time/date.rs +++ b/sqlx-core/src/postgres/types/time/date.rs @@ -7,6 +7,7 @@ use crate::postgres::{ }; use crate::types::Type; use std::mem; +use time::macros::format_description; use time::{Date, Duration}; impl Type for Date { @@ -42,7 +43,10 @@ impl<'r> Decode<'r, Postgres> for Date { PG_EPOCH + Duration::days(days.into()) } - PgValueFormat::Text => Date::parse(value.as_str()?, "%Y-%m-%d")?, + PgValueFormat::Text => Date::parse( + value.as_str()?, + &format_description!("[year]-[month]-[day]"), + )?, }) } } diff --git a/sqlx-core/src/postgres/types/time/datetime.rs b/sqlx-core/src/postgres/types/time/datetime.rs index 5950c58206..fc7bc928ad 100644 --- a/sqlx-core/src/postgres/types/time/datetime.rs +++ b/sqlx-core/src/postgres/types/time/datetime.rs @@ -8,7 +8,9 @@ use crate::postgres::{ use crate::types::Type; use std::borrow::Cow; use std::mem; -use time::{offset, Duration, OffsetDateTime, PrimitiveDateTime}; +use time::macros::format_description; +use time::macros::offset; +use time::{Duration, OffsetDateTime, PrimitiveDateTime}; impl Type for PrimitiveDateTime { fn type_info() -> PgTypeInfo { @@ -56,35 +58,28 @@ impl<'r> Decode<'r, Postgres> for PrimitiveDateTime { } PgValueFormat::Text => { - // If there are less than 9 digits after the decimal point - // We need to zero-pad - - // TODO: De-duplicate with MySQL - // TODO: Ask [time] to add a parse % for less-than-fixed-9 nanos - let s = value.as_str()?; - let s = if let Some(plus) = s.rfind('+') { - let mut big = String::from(&s[..plus]); - - while big.len() < 31 { - big.push('0'); - } - - big.push_str(&s[plus..]); - - Cow::Owned(big) - } else if s.len() < 31 { - if s.contains('.') { - Cow::Owned(format!("{:0<30}", s)) - } else { - Cow::Owned(format!("{}.000000000", s)) - } - } else { + // If there is no decimal point we need to add one. + let s = if s.contains('.') { Cow::Borrowed(s) + } else { + Cow::Owned(format!("{}.0", s)) }; - PrimitiveDateTime::parse(&*s, "%Y-%m-%d %H:%M:%S.%N")? + // Contains a time-zone specifier + // This is given for timestamptz for some reason + // Postgres already guarantees this to always be UTC + if s.contains('+') { + PrimitiveDateTime::parse(&*s, &format_description!("[year]-[month]-[day] [hour]:[minute]:[second].[subsecond][offset_hour]"))? + } else { + PrimitiveDateTime::parse( + &*s, + &format_description!( + "[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]" + ), + )? + } } }) } diff --git a/sqlx-core/src/postgres/types/time/mod.rs b/sqlx-core/src/postgres/types/time/mod.rs index 4dc334e8d4..1d3dc128e6 100644 --- a/sqlx-core/src/postgres/types/time/mod.rs +++ b/sqlx-core/src/postgres/types/time/mod.rs @@ -3,4 +3,4 @@ mod datetime; mod time; #[rustfmt::skip] -const PG_EPOCH: ::time::Date = ::time::date!(2000-1-1); +const PG_EPOCH: ::time::Date = ::time::macros::date!(2000-1-1); diff --git a/sqlx-core/src/postgres/types/time/time.rs b/sqlx-core/src/postgres/types/time/time.rs index 46c209b491..ff25586975 100644 --- a/sqlx-core/src/postgres/types/time/time.rs +++ b/sqlx-core/src/postgres/types/time/time.rs @@ -5,8 +5,8 @@ use crate::postgres::{ PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres, }; use crate::types::Type; -use std::borrow::Cow; use std::mem; +use time::macros::format_description; use time::{Duration, Time}; impl Type for Time { @@ -24,7 +24,7 @@ impl PgHasArrayType for Time { impl Encode<'_, Postgres> for Time { fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { // TIME is encoded as the microseconds since midnight - let us = (*self - Time::midnight()).whole_microseconds() as i64; + let us = (*self - Time::MIDNIGHT).whole_microseconds() as i64; Encode::::encode(&us, buf) } @@ -39,25 +39,13 @@ impl<'r> Decode<'r, Postgres> for Time { PgValueFormat::Binary => { // TIME is encoded as the microseconds since midnight let us = Decode::::decode(value)?; - Time::midnight() + Duration::microseconds(us) + Time::MIDNIGHT + Duration::microseconds(us) } - PgValueFormat::Text => { - // If there are less than 9 digits after the decimal point - // We need to zero-pad - - // FIXME: Ask [time] to add a parse % for less-than-fixed-9 nanos - - let s = value.as_str()?; - - let s = if s.len() < 20 { - Cow::Owned(format!("{:0<19}", s)) - } else { - Cow::Borrowed(s) - }; - - Time::parse(&*s, "%H:%M:%S.%N")? - } + PgValueFormat::Text => Time::parse( + value.as_str()?, + &format_description!("[hour]:[minute]:[second].[subsecond]"), + )?, }) } } diff --git a/sqlx-core/src/postgres/types/time_tz.rs b/sqlx-core/src/postgres/types/time_tz.rs index 0129f4825f..caba64cb7f 100644 --- a/sqlx-core/src/postgres/types/time_tz.rs +++ b/sqlx-core/src/postgres/types/time_tz.rs @@ -143,7 +143,7 @@ mod time { impl Encode<'_, Postgres> for PgTimeTz { fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull { let _ =