sfackler / rust-postgres

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

Dollar placeholder isn't replaced with actual value when value is a date #1065

Closed philwinn closed 12 months ago

philwinn commented 12 months ago

This minimal query

let date = [&NaiveDate::from_str("2020-01-01").unwrap() as &(dyn ToSql + Sync)];
let res = conn.execute("SELECT '$1'::date", &date).await.expect("FAILED");
println!("RESULT: {res}");

fails with the error

DEBUG tokio_postgres::prepare: preparing query s9: SELECT '$1'::date    
Error { kind: Db, cause: Some(DbError { severity: "ERROR", parsed_severity: Some(Error), code: SqlState(E22007), message: "invalid input syntax for type date: \"$1\"", detail: None, hint: None, position: Some(Original(8)), where_: None, schema: None, table: None, column: None, datatype: None, constraint: None, file: Some("datetime.c"), line: Some(4048), routine: Some("DateTimeParseError") }) }

What am I doing wrong here, why isn't $1 replaced with the actual value?

Additional info: From Cargo.toml: tokio-postgres = { version = "0.7.8", features = ["with-serde_json-1", "with-chrono-0_4", "array-impls"] }

sfackler commented 12 months ago

'$1' is the syntax for a string containing the characters $ and 1. $1 (without the quotes) is the syntax for a placeholder value.

philwinn commented 12 months ago

Thank you, removing the quotes actually works. My original problem though is the same problem but with a daterange instead. I tried do it like [...] @> '[{$1},{$2})'::daterange with the arguments values=[Date(1998-09-19), Date(1998-09-20)] (NaiveDates), but this also fails with

Error { kind: Db, cause: Some(DbError { severity: \"ERROR\", parsed_severity: Some(Error), code: SqlState(E22007), message: \"invalid input syntax for type date: \\\"$1\\\"\", detail: None, hint: None, position: Some(Original(161)), where_: None, schema: None, table: None, column: None, datatype: None, constraint: None, file: Some(\"datetime.c\"), line: Some(4048), routine: Some(\"DateTimeParseError\") }) }")

So I assume the correct query syntax is [...] @> $1::daterange (or without ::daterange), but then I don't know how to provide the range as a single value, expecially if the range is an unbounded interval (e.g. select '(1998-09-19,]'::daterange;). I have already searched the documentation, but couldn't find anything.

sfackler commented 12 months ago

I'd assume something like daterange($1, NULL, '(]'): https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-CONSTRUCT

philwinn commented 12 months ago

Thanks for pointing out the constructor functions, using these everything works fine now. Thanks again!