Closed Gbps closed 1 year ago
Thanks for reporting. The nullability is pretty limited but it should never be wrong like this. I suspect you're hitting triggering this case: https://github.com/jschaf/pggen/blob/main/internal/pginfer/nullability.go#L30.
Can you post the explain plan output?
Sorry for the late response, here it is:
Aggregate (cost=3.46..3.47 rows=1 width=32)
InitPlan 1 (returns $0)
-> Seq Scan on table1 (cost=0.00..1.01 rows=1 width=4)
Filter: ((val)::text = 'abc'::text)
-> Seq Scan on table2 (cost=0.00..2.23 rows=18 width=78)
Filter: (parse_id = $0)
Oh, the nullability doesn't account for the fact that aggregating a non-null column with no joins can still be null if no rows match.
Gotcha, understood. However, I'm still a bit confused since I thought that the default for when nullability was unknown that it would fall back to a nullable golang type. Is that not the case?
Is there a way I can explicitly tell the codegen that a particular arg is nullable or not? Maybe a second argument to pggen.arg
?
However, I'm still a bit confused since I thought that the default for when nullability was unknown that it would fall back to a nullable golang type. Is that not the case?
It turns out the nullability is working as intended. To verify, I added a test case in the linked commit, f664a91. I suspect the problem occurs when templating the Go code. There's some complexity in unwrapping types to get the variable declaration. We're probably aggressively pruning the type too aggressively. Consequently, we end up dropping the pointer type wrapper on the underlying string type. I'll investigate.
Is there a way I can explicitly tell the codegen that a particular arg is nullable or not? Maybe a second argument to pggen.arg?
No. I've tried very hard to avoid adding knobs since it complicates testing. Long term, I'd like to add a configuration system with the following traits.
I cut a new release, https://github.com/jschaf/pggen/releases/tag/2022-12-15, with the fix. Let me know if that doesn't do the trick.
Thank you for the fix! It looks like all is well now with queries using :one
, however the same problem seems to be present when converting the same kind of query to :many
. Just converting the same query to :many
should suffice for a repro.
Hey there, great project, I'm getting a lot of use out of it.
Here is the problem query:
Which generates this code:
Everything seems to be working great except that
row.Scan
is reading intovar item string
instead ofvar item *string
since it can be nullable. The functionality works as expected if there are two columns (it reads to a struct where the column is*string
) but when it's a single column return, it seems to forcerows.Scan
to read intostring
instead of*string
.I understand nullability inference is hard but that's not the problem here, since I believe it thinks this column should be nullable which is correct, but it just isn't generating the right code to read it into a nullable golang type.
Any suggestions?