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.
This commit is contained in:
Nikhil Benesch
2020-07-30 22:51:18 -04:00
parent bc682b3103
commit a30f0b6c05
2 changed files with 41 additions and 3 deletions

View File

@@ -12,7 +12,9 @@ fn base() -> NaiveDateTime {
impl<'a> FromSql<'a> for NaiveDateTime {
fn from_sql(_: &Type, raw: &[u8]) -> Result<NaiveDateTime, Box<dyn Error + Sync + Send>> {
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<FixedOffset> {
impl<'a> FromSql<'a> for NaiveDate {
fn from_sql(_: &Type, raw: &[u8]) -> Result<NaiveDate, Box<dyn Error + Sync + Send>> {
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);

View File

@@ -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<T>(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::<DateTime<Utc>>(&mut client, "'-infinity'", "timestamptz").await;
assert_overflows::<DateTime<Utc>>(&mut client, "'infinity'", "timestamptz").await;
assert_overflows::<NaiveDateTime>(&mut client, "'-infinity'", "timestamp").await;
assert_overflows::<NaiveDateTime>(&mut client, "'infinity'", "timestamp").await;
assert_overflows::<NaiveDate>(&mut client, "'-infinity'", "date").await;
assert_overflows::<NaiveDate>(&mut client, "'infinity'", "date").await;
}