using Postgres lateral_ with guard_ generates incorrect SQL
Opened this issue · 6 comments
It seems that using Postgres lateral_
and guard_
results in incorrect SQL.
At the end of the generated query, I see a clause:
WHERE ("t0"."res3") IS NOT DISTINCT FROM ("t0"."res5")
^-- (both referencing t0) ---^
This is odd as the guard_
clause references two different Entities with the ==.
operator.
Investigating this a bit further, it appears that all CROSS JOIN LATERAL
end up with an alias AS "t0"
.
Can you post a minimal query that produces incorrect SQL?
Here's a sample project which reproduces the issue: https://github.com/maerten/beam-issue-example
This is caused by buildQuery
in beam-core/Database/Beam/Query/SQL92.hs
assuming we can use the same table names in sub queries in joins, which is not a good assumption for lateral join. I think the proper approach is to thread the table prefix in buildQuery
so that we can disambiguate the names. I will put up a PR
Just pushed PR #647. @maerten would you mind verifying?
I did notice an error in your repository, you should use
deriving instance Show User
instead of
instance Show User
The former uses GHC's deriving mechanism to derive a proper implementation. The latter uses the default implementations in the Show
class which are mutually recursive, thus leads to a stack overflow.
@tathougies thanks for the fix, the fix works in the example project, and in another project too.
Expanding on the lateral_
queries, what's the right place to add limit the results of a lateral_
query?
I tried adding limit_
as shown in the example at https://hackage.haskell.org/package/beam-postgres-0.5.2.1/docs/Database-Beam-Postgres-Full.html#g:3
However that results in a type error:
• Couldn't match type ‘QBaseScope’
with ‘Database.Beam.Query.Internal.QNested QBaseScope’
And one last question, it looks like lateral_
always generates a CROSS LATERAL JOIN
, even when using a leftJoin_
.
This was unexpected to me, as the code for lateral_
looks like it would create different type of join if there is an 'on' clause. But perhaps I'm misunderstanding things..
My goal is to get something like a LATERAL LEFT JOIN
, so the query always some results even if the joined tables are empty.
(Let me know if you think these are bugs, and they should get their own github issues instead!)
-- expanding on https://github.com/maerten/beam-issue-example
testQuery2 = do
conn <- connectPostgreSQL "host=localhost dbname=testdb"
result <- runBeamPostgresDebug putStrLn conn $
runSelectReturningList $
select $ do
users <- all_ $ dbUsers myDb
Pg.lateral_ (users) $ \user -> do
-- using leftJoin, it still generates a CROSS LATERAL JOIN
post <- leftJoin_ (all_ $ dbPosts myDb) (\p -> (postUsername p ==. userName user))
return (user, post)
print result