sfackler / rust-postgres

Native PostgreSQL driver for the Rust programming language
Apache License 2.0
3.42k stars 436 forks source link

The f64::MAX conversion seems buggy #1090

Closed uuhan closed 6 months ago

uuhan commented 7 months ago

I have a structure contains the value f64::MAX, like

serde_json::json!({
    ... some othe fields ...
    "price": f64::MAX
});

It can be written into postgres as a jsonb:

select obj->'price' from t limit 1;
-[ RECORD 1 ]----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
price | 179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

But I can not read it back!

let rows = client.query("select obj from t limit 1", &[]).await?;
let r0: serde_json::Value = rows[0].get(0);

-- error retrieving column 0: error deserializing column 0: number out of range at line 1 column 1432

I tried to just read the f64::MAX field:

let rows = client.query("select obj->'price' from t limit 1", &[]).await?;
let r0: serde_json::Value = rows[0].get(0);

-- error retrieving column 0: error deserializing column 0: number out of range at line 1 column 309

Seems the field is read as a (integer) number ?

If I read this field as float8, this conversion can not be done right

let rows = client.query("select (obj->'price')::float8 from t limit 1", &[]).await?;
let r0: serde_json::Value = rows[0].get(0);

-- error retrieving column 0: error deserializing column 0: cannot convert between the Rust type `serde_json::value::Value` and the Postgres type `float8`

But the following conversion can be done right:

let rows = client.query("select (obj->'price')::float8 from t limit 1", &[]).await?;
let r0: f64 = rows[0].get(0);

-- 1.7976931348623157e308

version info:

[dependencies]
tokio-postgres = "0.7.6"
serde_json = "1.0.111"
sfackler commented 7 months ago

That sounds like an issue in PostgreSQL, not this library.

uuhan commented 7 months ago

That sounds like an issue in PostgreSQL, not this library.

@sfackler

Can this conversion serde_json::Value <-> f64 <-> Postgres float8 be handled correctly?

I find https://github.com/sfackler/rust-postgres/blob/bbc04145de7a83dfa66cb3cf4a68878da2c1cc32/postgres-types/src/lib.rs#L738 and https://github.com/sfackler/rust-postgres/blob/bbc04145de7a83dfa66cb3cf4a68878da2c1cc32/postgres-types/src/lib.rs#L1167

cannot convert between the Rust type serde_json::value::Value and the Postgres type float8

Is this above error excepted?

sfackler commented 7 months ago

Oh, this issue may actually be that Value is trying to deserialize the number as an integer rather than a float since Postgres isn't encoding it with a decimal point.

Using a strongly typed struct rather than Value would probably (?) fix that.