Skip to content
This repository was archived by the owner on Apr 25, 2023. It is now read-only.

Commit 042e341

Browse files
author
Julius de Bruijn
committed
Prevent float <-> decimal conversion on pg
It's unstable and will lead to tears.
1 parent 9d1fc75 commit 042e341

4 files changed

Lines changed: 19 additions & 76 deletions

File tree

db/test.db

0 Bytes
Binary file not shown.

src/connector/postgres/conversion.rs

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -511,36 +511,28 @@ impl<'a> ToSql for Value<'a> {
511511
(Value::Integer(integer), &PostgresType::OID) => integer.map(|integer| (integer as u32).to_sql(ty, out)),
512512
(Value::Integer(integer), _) => integer.map(|integer| (integer as i64).to_sql(ty, out)),
513513
(Value::Float(float), &PostgresType::FLOAT8) => float.map(|float| (float as f64).to_sql(ty, out)),
514-
#[cfg(feature = "bigdecimal")]
515-
(Value::Float(float), &PostgresType::NUMERIC) => float
516-
.map(|float| BigDecimal::from_f32(float).unwrap())
517-
.map(DecimalWrapper)
518-
.map(|dw| dw.to_sql(ty, out)),
514+
(Value::Float(_), &PostgresType::NUMERIC) => {
515+
let kind = ErrorKind::conversion(format!(
516+
"Writing a float to a {} column is unstable.",
517+
PostgresType::NUMERIC
518+
));
519+
return Err(Error::builder(kind).build().into());
520+
}
519521
(Value::Float(float), _) => float.map(|float| float.to_sql(ty, out)),
520522
(Value::Double(double), &PostgresType::FLOAT4) => double.map(|double| (double as f32).to_sql(ty, out)),
521-
#[cfg(feature = "bigdecimal")]
522-
(Value::Double(double), &PostgresType::NUMERIC) => double
523-
.map(|double| BigDecimal::from_f64(double).unwrap())
524-
.map(DecimalWrapper)
525-
.map(|dw| dw.to_sql(ty, out)),
523+
(Value::Double(_), &PostgresType::NUMERIC) => {
524+
let kind = ErrorKind::conversion(format!(
525+
"Writing a double to a {} column is unstable.",
526+
PostgresType::NUMERIC
527+
));
528+
return Err(Error::builder(kind).build().into());
529+
}
526530
(Value::Double(double), _) => double.map(|double| double.to_sql(ty, out)),
527-
#[cfg(feature = "bigdecimal")]
528-
(Value::Numeric(decimal), &PostgresType::FLOAT4) => decimal.as_ref().map(|decimal| {
529-
let f = decimal.to_string().parse::<f32>().expect("decimal to f32 conversion");
530-
f.to_sql(ty, out)
531-
}),
532-
#[cfg(feature = "bigdecimal")]
533-
(Value::Numeric(decimal), &PostgresType::FLOAT8) => decimal.as_ref().map(|decimal| {
534-
let f = decimal.to_string().parse::<f64>().expect("decimal to f64 conversion");
535-
f.to_sql(ty, out)
536-
}),
537-
#[cfg(feature = "bigdecimal")]
538531
(Value::Array(values), &PostgresType::FLOAT4_ARRAY) => values.as_ref().map(|values| {
539532
let mut floats = Vec::with_capacity(values.len());
540533

541534
for value in values.iter() {
542535
let float = match value {
543-
Value::Numeric(n) => n.as_ref().and_then(|n| n.to_string().parse::<f32>().ok()),
544536
Value::Float(f) => *f,
545537
Value::Double(d) => d.map(|d| d as f32),
546538
v => {
@@ -558,13 +550,11 @@ impl<'a> ToSql for Value<'a> {
558550

559551
floats.to_sql(ty, out)
560552
}),
561-
#[cfg(feature = "bigdecimal")]
562553
(Value::Array(values), &PostgresType::FLOAT8_ARRAY) => values.as_ref().map(|values| {
563554
let mut floats = Vec::with_capacity(values.len());
564555

565556
for value in values.iter() {
566557
let float = match value {
567-
Value::Numeric(n) => n.as_ref().and_then(|n| n.to_string().parse::<f64>().ok()),
568558
Value::Float(f) => f.map(|f| f as f64),
569559
Value::Double(d) => *d,
570560
v => {
@@ -598,9 +588,10 @@ impl<'a> ToSql for Value<'a> {
598588
.as_ref()
599589
.map(|decimal| DecimalWrapper(decimal.clone()).to_sql(ty, out)),
600590
#[cfg(feature = "bigdecimal")]
601-
(Value::Numeric(float), _) => float
602-
.as_ref()
603-
.map(|float| DecimalWrapper(float.clone()).to_sql(ty, out)),
591+
(Value::Numeric(_), typ) => {
592+
let kind = ErrorKind::conversion(format!("Writing a decimal to a {} column is unstable.", typ));
593+
return Err(Error::builder(kind).build().into());
594+
}
604595
#[cfg(feature = "uuid")]
605596
(Value::Text(string), &PostgresType::UUID) => string.as_ref().map(|string| {
606597
let parsed_uuid: Uuid = string.parse()?;

src/tests/query.rs

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,7 +1896,6 @@ async fn ints_read_write_to_numeric(api: &mut dyn TestApi) -> crate::Result<()>
18961896
let table = api.create_table("id int, value numeric(12,2)").await?;
18971897

18981898
let insert = Insert::multi_into(&table, &["id", "value"])
1899-
.values(vec![Value::integer(1), Value::double(1234.5)])
19001899
.values(vec![Value::integer(2), Value::integer(1234)])
19011900
.values(vec![Value::integer(3), Value::integer(12345)]);
19021901

@@ -1907,37 +1906,10 @@ async fn ints_read_write_to_numeric(api: &mut dyn TestApi) -> crate::Result<()>
19071906

19081907
for (i, row) in rows.into_iter().enumerate() {
19091908
match i {
1910-
0 => assert_eq!(Value::numeric(BigDecimal::from_str("1234.5").unwrap()), row["value"]),
1911-
1 => assert_eq!(Value::numeric(BigDecimal::from_str("1234.0").unwrap()), row["value"]),
1909+
0 => assert_eq!(Value::numeric(BigDecimal::from_str("1234.0").unwrap()), row["value"]),
19121910
_ => assert_eq!(Value::numeric(BigDecimal::from_str("12345.0").unwrap()), row["value"]),
19131911
}
19141912
}
19151913

19161914
Ok(())
19171915
}
1918-
1919-
#[cfg(feature = "bigdecimal")]
1920-
#[test_each_connector(tags("postgresql"))]
1921-
async fn bigdecimal_read_write_to_floating(api: &mut dyn TestApi) -> crate::Result<()> {
1922-
use bigdecimal::BigDecimal;
1923-
use std::str::FromStr;
1924-
1925-
let table = api.create_table("id int, a float4, b float8").await?;
1926-
let val = BigDecimal::from_str("0.1").unwrap();
1927-
1928-
let insert = Insert::multi_into(&table, &["id", "a", "b"]).values(vec![
1929-
Value::integer(1),
1930-
Value::numeric(val.clone()),
1931-
Value::numeric(val.clone()),
1932-
]);
1933-
1934-
api.conn().execute(insert.into()).await?;
1935-
1936-
let select = Select::from_table(&table);
1937-
let row = api.conn().select(select).await?.into_single()?;
1938-
1939-
assert_eq!(Value::float(0.1), row["a"]);
1940-
assert_eq!(Value::double(0.1), row["b"]);
1941-
1942-
Ok(())
1943-
}

src/tests/types/postgres/bigdecimal.rs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -186,23 +186,3 @@ test_type!(money_array(
186186
Value::Array(None),
187187
Value::array(vec![BigDecimal::from_str("1.12")?, BigDecimal::from_str("1.12")?])
188188
));
189-
190-
test_type!(float4(
191-
postgresql,
192-
"float4",
193-
(Value::Numeric(None), Value::Float(None)),
194-
(
195-
Value::numeric(BigDecimal::from_str("1.123456")?),
196-
Value::float(1.123456)
197-
)
198-
));
199-
200-
test_type!(float8(
201-
postgresql,
202-
"float8",
203-
(Value::Numeric(None), Value::Double(None)),
204-
(
205-
Value::numeric(BigDecimal::from_str("1.123456")?),
206-
Value::double(1.123456)
207-
)
208-
));

0 commit comments

Comments
 (0)