diff --git a/Database/SQLite/Simple.hs b/Database/SQLite/Simple.hs
--- a/Database/SQLite/Simple.hs
+++ b/Database/SQLite/Simple.hs
@@ -64,6 +64,7 @@
     -- * Queries that return results
   , query
   , query_
+  , queryWith_
   , queryNamed
   , lastInsertRowId
     -- * Queries that stream results
@@ -88,8 +89,10 @@
   , withBind
   , nextRow
     -- ** Exceptions
-  , FormatError(fmtMessage, fmtQuery, fmtParams)
-  , ResultError(errSQLType, errHaskellType, errMessage)
+  , FormatError(..)
+  , ResultError(..)
+  , Base.SQLError(..)
+  , Base.Error(..)
   ) where
 
 import           Control.Applicative
@@ -303,9 +306,9 @@
     void . Base.step $ stmt
 
 
-doFoldToList :: (FromRow row) => Statement -> IO [row]
-doFoldToList stmt =
-  fmap reverse $ doFold stmt [] (\acc e -> return (e : acc))
+doFoldToList :: RowParser row -> Statement -> IO [row]
+doFoldToList fromRow_ stmt =
+  fmap reverse $ doFold fromRow_ stmt [] (\acc e -> return (e : acc))
 
 -- | Perform a @SELECT@ or other SQL query that is expected to return
 -- results. All results are retrieved and converted before this
@@ -323,13 +326,18 @@
          => Connection -> Query -> q -> IO [r]
 query conn templ qs =
   withStatementParams conn templ qs $ \stmt ->
-    doFoldToList stmt
+    doFoldToList fromRow stmt
 
 -- | A version of 'query' that does not perform query substitution.
 query_ :: (FromRow r) => Connection -> Query -> IO [r]
-query_ conn query =
-  withStatement conn query doFoldToList
+query_ = queryWith_ fromRow
 
+-- | A version of 'query' that does not perform query substitution and
+-- takes an explicit 'RowParser'.
+queryWith_ :: RowParser r -> Connection -> Query -> IO [r]
+queryWith_ fromRow_ conn query =
+  withStatement conn query (doFoldToList fromRow_)
+
 -- | A version of 'query' where the query parameters (placeholders)
 -- are named.
 --
@@ -340,7 +348,7 @@
 -- @
 queryNamed :: (FromRow r) => Connection -> Query -> [NamedParam] -> IO [r]
 queryNamed conn templ params =
-  withStatementNamedParams conn templ params $ \stmt -> doFoldToList stmt
+  withStatementNamedParams conn templ params $ \stmt -> doFoldToList fromRow stmt
 
 -- | A version of 'execute' that does not perform query substitution.
 execute_ :: Connection -> Query -> IO ()
@@ -376,7 +384,7 @@
         -> IO a
 fold conn query params initalState action =
   withStatementParams conn query params $ \stmt ->
-    doFold stmt initalState action
+    doFold fromRow stmt initalState action
 
 -- | A version of 'fold' which does not perform parameter substitution.
 fold_ :: ( FromRow row )
@@ -387,7 +395,7 @@
         -> IO a
 fold_ conn query initalState action =
   withStatement conn query $ \stmt ->
-    doFold stmt initalState action
+    doFold fromRow stmt initalState action
 
 -- | A version of 'fold' where the query parameters (placeholders) are
 -- named.
@@ -400,14 +408,14 @@
           -> IO a
 foldNamed conn query params initalState action =
   withStatementNamedParams conn query params $ \stmt ->
-    doFold stmt initalState action
+    doFold fromRow stmt initalState action
 
-doFold :: (FromRow row) => Statement ->  a -> (a -> row -> IO a) -> IO a
-doFold stmt initState action =
+doFold :: RowParser row -> Statement ->  a -> (a -> row -> IO a) -> IO a
+doFold fromRow_ stmt initState action =
   loop initState
   where
     loop val = do
-      maybeNextRow <- nextRow stmt
+      maybeNextRow <- nextRowWith fromRow_ stmt
       case maybeNextRow of
         Just row  -> do
           val' <- action val row
@@ -416,20 +424,23 @@
 
 -- | Extracts the next row from the prepared statement.
 nextRow :: (FromRow r) => Statement -> IO (Maybe r)
-nextRow (Statement stmt) = do
+nextRow = nextRowWith fromRow
+
+nextRowWith :: RowParser r -> Statement -> IO (Maybe r)
+nextRowWith fromRow_ (Statement stmt) = do
   statRes <- Base.step stmt
   case statRes of
     Base.Row -> do
       rowRes <- Base.columns stmt
       let nCols = length rowRes
-      row <- convertRow rowRes nCols
+      row <- convertRow fromRow_ rowRes nCols
       return $ Just row
     Base.Done -> return Nothing
 
-convertRow :: (FromRow r) => [Base.SQLData] -> Int -> IO r
-convertRow rowRes ncols = do
+convertRow :: RowParser r -> [Base.SQLData] -> Int -> IO r
+convertRow fromRow_ rowRes ncols = do
   let rw = RowParseRO ncols
-  case runStateT (runReaderT (unRP fromRow) rw) (0, rowRes) of
+  case runStateT (runReaderT (unRP fromRow_) rw) (0, rowRes) of
     Ok (val,(col,_))
        | col == ncols -> return val
        | otherwise -> errorColumnMismatch (ColumnOutOfBounds col)
@@ -493,34 +504,39 @@
       Query . maybe "no query string" (\(BaseD.Utf8 s) -> TE.decodeUtf8 s)
 
 -- $use
--- Create a test database by copy pasting the below snippet to your
--- shell:
---
--- @
--- sqlite3 test.db \"CREATE TABLE test (id INTEGER PRIMARY KEY, str text); \\
--- INSERT INTO test (str) VALUES ('test string');\"
--- @
---
--- ..and access it from Haskell:
+-- An example that creates a table 'test', inserts a couple of rows
+-- and proceeds to showcase how to update or delete rows.  This
+-- example also demonstrates the use of 'lastInsertRowId' (how to
+-- refer to a previously inserted row) and 'executeNamed' (an easier
+-- to maintain form of query parameter naming).
 --
--- > {-# LANGUAGE OverloadedStrings #-}
+-- >{-# LANGUAGE OverloadedStrings #-}
 -- >
--- > import Control.Applicative
--- > import Database.SQLite.Simple
--- > import Database.SQLite.Simple.FromRow
+-- >import           Control.Applicative
+-- >import qualified Data.Text as T
+-- >import           Database.SQLite.Simple
+-- >import           Database.SQLite.Simple.FromRow
 -- >
--- > data TestField = TestField Int String deriving (Show)
+-- >data TestField = TestField Int T.Text deriving (Show)
 -- >
--- > instance FromRow TestField where
--- >   fromRow = TestField <$> field <*> field
+-- >instance FromRow TestField where
+-- >  fromRow = TestField <$> field <*> field
 -- >
--- > main :: IO ()
--- > main = do
--- >   conn <- open "test.db"
--- >   execute conn "INSERT INTO test (str) VALUES (?)" (Only ("test string 2" :: String))
--- >   r <- query_ conn "SELECT * from test" :: IO [TestField]
--- >   mapM_ print r
--- >   close conn
+-- >instance ToRow TestField where
+-- >  toRow (TestField id_ str) = toRow (id_, str)
+-- >
+-- >main :: IO ()
+-- >main = do
+-- >  conn <- open "test.db"
+-- >  execute_ conn "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, str TEXT)"
+-- >  execute conn "INSERT INTO test (str) VALUES (?)" (Only ("test string 2" :: String))
+-- >  execute conn "INSERT INTO test (id, str) VALUES (?,?)" (TestField 13 "test string 3")
+-- >  rowId <- lastInsertRowId conn
+-- >  executeNamed conn "UPDATE test SET str = :str WHERE id = :id" [":str" := ("updated str" :: T.Text), ":id" := rowId]
+-- >  r <- query_ conn "SELECT * from test" :: IO [TestField]
+-- >  mapM_ print r
+-- >  execute conn "DELETE FROM test WHERE id = ?" (Only rowId)
+-- >  close conn
 
 -- $querytype
 --
diff --git a/changelog b/changelog
--- a/changelog
+++ b/changelog
@@ -1,3 +1,9 @@
+0.4.9.0
+	* Provide queryWith_ to allow more fine-grained access to
+	  constructing queries.
+	* Expose error data constructors (pull request #42)
+	* Improve haddocks
+
 0.4.8.0
 	* Export `bindNamed'
 
diff --git a/sqlite-simple.cabal b/sqlite-simple.cabal
--- a/sqlite-simple.cabal
+++ b/sqlite-simple.cabal
@@ -1,5 +1,5 @@
 Name:                sqlite-simple
-Version:             0.4.8.0
+Version:             0.4.9.0
 Synopsis:            Mid-Level SQLite client library
 Description:
     Mid-level SQLite client library, based on postgresql-simple.
