-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Double left join -> wrong NULL inference -> runtime exception. #2796
Comments
@Palmik can you please post the output of |
|
Hi, are you able to reproduce? |
I ran into this as well on my project with similar table structure & joins. What I discovered is using |
Hello! I ran into this issue with a single left join. create table a (
id_a text primary key not null
);
create table b (
id_b text primary key not null,
id_a text references a (id_a)
);
insert into b (id_b) values ('1'); use serde::Deserialize;
use sqlx::{postgres::PgPoolOptions, query_as};
#[derive(Debug, Deserialize)]
pub struct Rows {
pub id_a: Option<String>,
}
#[tokio::main]
async fn main() {
let db = PgPoolOptions::new().connect("postgresql://127.0.0.1/labs").await.unwrap();
query_as!(
Rows,
r#"
select a.id_a
from b
left join a on a.id_a = b.id_a
where b.id_b = $1
"#,
"1"
)
.fetch_all(&db)
.await
.unwrap();
} the query plan: [
{
"Plan": {
"Node Type": "Nested Loop",
"Parallel Aware": false,
"Async Capable": false,
"Join Type": "Left",
"Startup Cost": 0.3,
"Total Cost": 16.35,
"Plan Rows": 1,
"Plan Width": 32,
"Output": ["a.id_a"],
"Inner Unique": true,
"Plans": [
{
"Node Type": "Index Scan",
"Parent Relationship": "Outer",
"Parallel Aware": false,
"Async Capable": false,
"Scan Direction": "Forward",
"Index Name": "b_pkey",
"Relation Name": "b",
"Schema": "public",
"Alias": "b",
"Startup Cost": 0.15,
"Total Cost": 8.17,
"Plan Rows": 1,
"Plan Width": 32,
"Output": ["b.id_b", "b.id_a"],
"Index Cond": "(b.id_b = '1'::text)"
},
{
"Node Type": "Index Only Scan",
"Parent Relationship": "Inner",
"Parallel Aware": false,
"Async Capable": false,
"Scan Direction": "Forward",
"Index Name": "a_pkey",
"Relation Name": "a",
"Schema": "public",
"Alias": "a",
"Startup Cost": 0.15,
"Total Cost": 8.17,
"Plan Rows": 1,
"Plan Width": 32,
"Output": ["a.id_a"],
"Index Cond": "(a.id_a = b.id_a)"
}
]
}
}
] It works correctly if I force the id_a as optionnal : query_as!(
Rows,
r#"
select a.id_a as "id_a?"
from b
left join a on a.id_a = b.id_a
where b.id_b = $1
"#,
"1"
)
.fetch_all(&db)
.await
.unwrap() Strangely, it also works without the parameter binding: query_as!(
Rows,
r#"
select a.id_a
from b
left join a on a.id_a = b.id_a
where b.id_b = '1'
"#,
)
.fetch_all(&db)
.await
.unwrap(); |
Edit: I got my many-to-many work: |
Bug Description
Double left join leads to faulty Option / nullability inference. I have provided a minimal repro.
There are two nullability inference issues:
Minimal Reproduction
https://github.com/Palmik/sqlx-issue-repro
The schema:
The sql query:
You would expect
foo.id
andfoo.name
to not be optional, and the other columns to be optional. SQLx infersfoo.*
andbaz.*
as optional, andbar.*
as not optional. One can circumvent the issue by using theAS "bar_id?"
syntax to mark the columns as optional manually.Running the code produces:
If you make sure that all rows exist, e.g. commenting out line
27
, you get:Info
0.7.2
sqlx = { version = "0.7.2", features = ["postgres", "uuid", "runtime-tokio-native-tls"] }
rustc --version
:rustc 1.71.1 (eb26296b5 2023-08-03)
The text was updated successfully, but these errors were encountered: