diff --git a/hasql-th.cabal b/hasql-th.cabal
--- a/hasql-th.cabal
+++ b/hasql-th.cabal
@@ -1,5 +1,5 @@
 name: hasql-th
-version: 0.4.0.3
+version: 0.4.0.4
 category: Hasql, Database, PostgreSQL, Template Haskell
 synopsis: Template Haskell utilities for Hasql
 description:
diff --git a/library/Hasql/TH.hs b/library/Hasql/TH.hs
--- a/library/Hasql/TH.hs
+++ b/library/Hasql/TH.hs
@@ -129,11 +129,16 @@
 -------------------------
 
 {-|
+@
+:: `Statement` params row
+@
+
 Statement producing exactly one result row.
 
-Will raise `Hasql.Session.UnexpectedAmountOfRows` error if it's any other.
+Will cause the running session to fail with the
+`Hasql.Session.UnexpectedAmountOfRows` error if it's any other.
 
-=== Examples
+=== __Examples__
 
 >>> :t [singletonStatement|select 1 :: int2|]
 ... :: Statement () Int16
@@ -162,8 +167,14 @@
 singletonStatement = statementExp Exp.singletonStatement Extraction.statement
 
 {-|
+@
+:: `Statement` params (Maybe row)
+@
+
 Statement producing one row or none.
 
+=== __Examples__
+
 >>> :t [maybeStatement|select 1 :: int2|]
 ... :: Statement () (Maybe Int16)
 -}
@@ -171,8 +182,14 @@
 maybeStatement = statementExp Exp.maybeStatement Extraction.statement
 
 {-|
+@
+:: `Statement` params (`Vector` row)
+@
+
 Statement producing a vector of rows.
 
+=== __Examples__
+
 >>> :t [vectorStatement|select 1 :: int2|]
 ... :: Statement () (Vector Int16)
 -}
@@ -180,9 +197,15 @@
 vectorStatement = statementExp Exp.vectorStatement Extraction.statement
 
 {-|
+@
+:: `Fold` row folding -> `Statement` params folding
+@
+
 Function from `Fold` over rows to a statement producing the result of folding.
 Use this when you need to aggregate rows customly.
 
+=== __Examples__
+
 >>> :t [foldStatement|select 1 :: int2|]
 ... :: Fold Int16 b -> Statement () b
 -}
@@ -190,8 +213,14 @@
 foldStatement = statementExp Exp.foldStatement Extraction.statement
 
 {-|
+@
+:: `Statement` params ()
+@
+
 Statement producing no results.
 
+=== __Examples__
+
 >>> :t [resultlessStatement|insert into "user" (name, email) values ($1 :: text, $2 :: text)|]
 ...
 ... :: Statement (Text, Text) ()
@@ -200,7 +229,13 @@
 resultlessStatement = statementExp Exp.resultlessStatement Extraction.rowlessStatement
 
 {-|
+@
+:: `Statement` params Int64
+@
+
 Statement counting the rows it affects.
+
+=== __Examples__
 
 >>> :t [rowsAffectedStatement|delete from "user" where password is null|]
 ...
diff --git a/library/Hasql/TH/Syntax/Parsing.hs b/library/Hasql/TH/Syntax/Parsing.hs
--- a/library/Hasql/TH/Syntax/Parsing.hs
+++ b/library/Hasql/TH/Syntax/Parsing.hs
@@ -619,9 +619,21 @@
 JoinTableRef (MethJoinedTable (QualJoinMeth...
 
 -}
-tableRef = label "table reference" $ do
-  _tr <- nonTrailingTableRef
-  (space1 *> trailingTableRef _tr) <|> pure _tr
+tableRef =
+  label "table reference" $ 
+  do
+    _tr <- nonTrailingTableRef
+    recur _tr
+  where
+    recur _tr =
+      asum [
+          do
+            _tr2 <- wrapToHead (space1 *> trailingTableRef _tr)
+            endHead
+            recur _tr2
+          ,
+          pure _tr
+        ]
 
 nonTrailingTableRef = asum [
     lateralTableRef <|>
@@ -809,14 +821,26 @@
   ]
 
 joinedTable =
-  asum [
-      do
-        _tr1 <- wrapToHead nonTrailingTableRef
-        space1
-        trailingJoinedTable _tr1
-      ,
-      inParensJoinedTable
-    ]
+  head >>= tail
+  where
+    head =
+      asum [
+          do
+            _tr <- wrapToHead nonTrailingTableRef
+            space1
+            trailingJoinedTable _tr
+          ,
+          inParensJoinedTable
+        ]
+    tail _jt =
+      asum [
+          do
+            _jt2 <- wrapToHead (space1 *> trailingJoinedTable (JoinTableRef _jt Nothing))
+            endHead
+            tail _jt2
+          ,
+          pure _jt
+        ]
 
 {-
   | '(' joined_table ')'
@@ -835,7 +859,7 @@
       keyphrase "cross join"
       endHead
       space1
-      _tr2 <- tableRef
+      _tr2 <- nonTrailingTableRef
       return (MethJoinedTable CrossJoinMeth _tr1 _tr2)
     ,
     do
@@ -853,7 +877,7 @@
       space1
       _jt <- joinTypedJoin
       space1
-      _tr2 <- tableRef
+      _tr2 <- nonTrailingTableRef
       return (MethJoinedTable (NaturalJoinMeth _jt) _tr1 _tr2)
   ]
   where
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -13,6 +13,24 @@
 
 
 main = defaultMain [
+    checkParallel $ Group "Bug-fixes" $ let
+      parsesFine testName sql =
+        (,) (testName <> " parses fine") $ property $ test $ do
+          footnote (Text.unpack sql)
+          case Parsing.run Parsing.preparableStmt sql of
+            Left err -> do
+              footnote err
+              failure
+            Right _ -> success
+      in [
+          parsesFine "Multiple inner joins"
+            "select i :: int8 from auth.user as u\n\
+            \inner join edgenode.usere_provider as p\n\
+            \on u.id = p.user_id\n\
+            \inner join edgenode.provider_branch as b\n\
+            \on b.provider_fk = p.provider_id"
+        ]
+    ,
     checkParallel $ Group "Parsing a rendered AST produces the same AST" $ let
       p _name _amount _gen _parser _renderer =
         (,) _name $ withDiscards (fromIntegral _amount * 200) $ withTests _amount $ property $ do
diff --git a/test/Main/Gen.hs b/test/Main/Gen.hs
--- a/test/Main/Gen.hs
+++ b/test/Main/Gen.hs
@@ -264,7 +264,7 @@
 
 joinedTable = frequency [
     (5,) $ InParensJoinedTable <$> joinedTable,
-    (95,) $ MethJoinedTable <$> joinMeth <*> choice [relationExprTableRef, selectTableRef, funcTableRef] <*> tableRef
+    (95,) $ MethJoinedTable <$> joinMeth <*> tableRef <*> choice [relationExprTableRef, selectTableRef, funcTableRef]
   ]
 
 joinMeth = choice [
