@@ -66,9 +66,9 @@ module Database.PostgreSQL.Simple
66 -- ** Exceptions
66 -- ** Exceptions
67 , SqlError(..)
67 , SqlError(..)
68 , PQ.ExecStatus(..)
68 , PQ.ExecStatus(..)
69− , FormatError(fmtMessage, fmtQuery, fmtParams)
69+ , FormatError(..)
70− , QueryError(qeMessage, qeQuery)
70+ , QueryError(..)
71− , ResultError(errSQLType, errHaskellType, errMessage)
71+ , ResultError(..)
72 -- * Connection management
72 -- * Connection management
73 , Base.connectPostgreSQL
73 , Base.connectPostgreSQL
74 , Base.close
74 , Base.close
@@ -114,19 +114,18 @@ import Blaze.ByteString.Builder
114 ( Builder, fromByteString, toByteString )
114 ( Builder, fromByteString, toByteString )
115import Blaze.ByteString.Builder.Char8 (fromChar)
115import Blaze.ByteString.Builder.Char8 (fromChar)
116import Blaze.Text ( integral )
116import Blaze.Text ( integral )
117−import Control.Applicative ((<$>), pure)
117+import Control.Applicative ((<$>))
118import Control.Exception as E
118import Control.Exception as E
119import Control.Monad (foldM)
119import Control.Monad (foldM)
120import Data.ByteString (ByteString)
120import Data.ByteString (ByteString)
121import Data.Int (Int64)
121import Data.Int (Int64)
122import Data.List (intersperse)
122import Data.List (intersperse)
123import Data.Monoid (mconcat)
123import Data.Monoid (mconcat)
124−import Data.Typeable (Typeable)
125import Database.PostgreSQL.Simple.Compat ( (<>) )
124import Database.PostgreSQL.Simple.Compat ( (<>) )
126import Database.PostgreSQL.Simple.FromField (ResultError(..))
125import Database.PostgreSQL.Simple.FromField (ResultError(..))
127import Database.PostgreSQL.Simple.FromRow (FromRow(..))
126import Database.PostgreSQL.Simple.FromRow (FromRow(..))
128import Database.PostgreSQL.Simple.Ok
127import Database.PostgreSQL.Simple.Ok
129−import Database.PostgreSQL.Simple.ToField (Action(..), inQuotes)
128+import Database.PostgreSQL.Simple.ToField (Action(..))
130import Database.PostgreSQL.Simple.ToRow (ToRow(..))
129import Database.PostgreSQL.Simple.ToRow (ToRow(..))
131import Database.PostgreSQL.Simple.Types
130import Database.PostgreSQL.Simple.Types
132 ( Binary(..), In(..), Only(..), Query(..), (:.)(..) )
131 ( Binary(..), In(..), Only(..), Query(..), (:.)(..) )
@@ -135,21 +134,9 @@ import Database.PostgreSQL.Simple.Transaction
135import Database.PostgreSQL.Simple.TypeInfo
134import Database.PostgreSQL.Simple.TypeInfo
136import qualified Database.PostgreSQL.LibPQ as PQ
135import qualified Database.PostgreSQL.LibPQ as PQ
137import qualified Data.ByteString.Char8 as B
136import qualified Data.ByteString.Char8 as B
138−import qualified Data.Text as T
139−import qualified Data.Text.Encoding as TE
140import Control.Monad.Trans.Reader
137import Control.Monad.Trans.Reader
141import Control.Monad.Trans.State.Strict
138import Control.Monad.Trans.State.Strict
143−-- | Exception thrown if a 'Query' could not be formatted correctly.
144−-- This may occur if the number of \'@?@\' characters in the query
145−-- string does not match the number of parameters provided.
146−data FormatError = FormatError {
147− fmtMessage :: String
149− , fmtParams :: [ByteString]
150− } deriving (Eq, Show, Typeable)
152−instance Exception FormatError
154-- | Format a query string.
141-- | Format a query string.
@@ -286,40 +273,17 @@ parseTemplate template =
287 skipSpace = B.dropWhile isSpace_ascii
274 skipSpace = B.dropWhile isSpace_ascii
289−escapeStringConn :: Connection -> ByteString -> IO (Either ByteString ByteString)
290−escapeStringConn = escapeWrap PQ.escapeStringConn
292−escapeIdentifier :: Connection -> ByteString -> IO (Either ByteString ByteString)
293−escapeIdentifier = escapeWrap PQ.escapeIdentifier
295−escapeByteaConn :: Connection -> ByteString -> IO (Either ByteString ByteString)
296−escapeByteaConn = escapeWrap PQ.escapeByteaConn
298−escapeWrap :: (PQ.Connection -> ByteString -> IO (Maybe ByteString))
301− -> IO (Either ByteString ByteString)
302−escapeWrap f conn s =
303− withConnection conn $ \c ->
304− f c s >>= checkError c
306−checkError :: PQ.Connection -> Maybe a -> IO (Either ByteString a)
307−checkError _ (Just x) = return $ Right x
308−checkError c Nothing = Left . maybe "" id <$> PQ.errorMessage c
310buildQuery :: Connection -> Query -> ByteString -> [Action] -> IO Builder
278buildQuery :: Connection -> Query -> ByteString -> [Action] -> IO Builder
311−buildQuery conn q template xs = zipParams (split template) <$> mapM sub xs
279+buildQuery conn q template xs =
312− where err' msg = fmtError (utf8ToString msg) q xs
280+ zipParams (split template) <$> mapM (buildAction conn q xs) xs
313− quote = either err' (inQuotes . fromByteString)
281+ where split s =
314− utf8ToString = T.unpack . TE.decodeUtf8
282+ let (h,t) = B.break (=='?') s
315− sub (Plain b) = pure b
283+ in fromByteString h
316− sub (Escape s) = quote <$> escapeStringConn conn s
284+ : if B.null t
317− sub (EscapeByteA s) = quote <$> escapeByteaConn conn s
285+ then []
318− sub (EscapeIdentifier s) = either err' fromByteString <$>
319− escapeIdentifier conn s
320− sub (Many ys) = mconcat <$> mapM sub ys
321− split s = fromByteString h : if B.null t then [] else split (B.tail t)
286+ else split (B.tail t)
322− where (h,t) = B.break (=='?') s
323 zipParams (t:ts) (p:ps) = t <> p <> zipParams ts ps
287 zipParams (t:ts) (p:ps) = t <> p <> zipParams ts ps
324 zipParams [t] [] = t
288 zipParams [t] [] = t
325 zipParams _ _ = fmtError (show (B.count '?' template) ++
289 zipParams _ _ = fmtError (show (B.count '?' template) ++
@@ -659,17 +623,6 @@ ellipsis bs
659 | B.length bs > 15 = B.take 10 bs `B.append` "[...]"
623 | B.length bs > 15 = B.take 10 bs `B.append` "[...]"
660 | otherwise = bs
624 | otherwise = bs
662−fmtError :: String -> Query -> [Action] -> a
663−fmtError msg q xs = throw FormatError {
666− , fmtParams = map twiddle xs
668− where twiddle (Plain b) = toByteString b
669− twiddle (Escape s) = s
670− twiddle (EscapeByteA s) = s
671− twiddle (EscapeIdentifier s) = s
672− twiddle (Many ys) = B.concat (map twiddle ys)