@@ -118,30 +118,26 @@ module Database.PostgreSQL.Simple
118 , formatQuery
118 , formatQuery
121−import Data.ByteString.Builder
121+import Data.ByteString.Builder (Builder, byteString, char8)
122− ( Builder, byteString, char8, intDec )
123import Control.Applicative ((<$>))
122import Control.Applicative ((<$>))
124import Control.Exception as E
123import Control.Exception as E
125−import Control.Monad (unless)
126import Data.ByteString (ByteString)
124import Data.ByteString (ByteString)
127import Data.Int (Int64)
125import Data.Int (Int64)
128import Data.List (intersperse)
126import Data.List (intersperse)
129import Data.Monoid (mconcat)
127import Data.Monoid (mconcat)
130−import Database.PostgreSQL.Simple.Compat ( (<>), toByteString )
128+import Database.PostgreSQL.Simple.Compat ((<>), toByteString)
129+import Database.PostgreSQL.Simple.Cursor
131import Database.PostgreSQL.Simple.FromField (ResultError(..))
130import Database.PostgreSQL.Simple.FromField (ResultError(..))
132import Database.PostgreSQL.Simple.FromRow (FromRow(..))
131import Database.PostgreSQL.Simple.FromRow (FromRow(..))
133−import Database.PostgreSQL.Simple.Ok
134import Database.PostgreSQL.Simple.ToField (Action(..))
132import Database.PostgreSQL.Simple.ToField (Action(..))
135import Database.PostgreSQL.Simple.ToRow (ToRow(..))
133import Database.PostgreSQL.Simple.ToRow (ToRow(..))
136import Database.PostgreSQL.Simple.Types
134import Database.PostgreSQL.Simple.Types
137 ( Binary(..), In(..), Only(..), Query(..), (:.)(..) )
135 ( Binary(..), In(..), Only(..), Query(..), (:.)(..) )
138import Database.PostgreSQL.Simple.Internal as Base
136import Database.PostgreSQL.Simple.Internal as Base
137+import Database.PostgreSQL.Simple.Internal.PQResultUtils
139import Database.PostgreSQL.Simple.Transaction
138import Database.PostgreSQL.Simple.Transaction
140−import Database.PostgreSQL.Simple.TypeInfo
141import qualified Database.PostgreSQL.LibPQ as PQ
139import qualified Database.PostgreSQL.LibPQ as PQ
142import qualified Data.ByteString.Char8 as B
140import qualified Data.ByteString.Char8 as B
143−import Control.Monad.Trans.Reader
144−import Control.Monad.Trans.State.Strict
147-- | Format a query string.
143-- | Format a query string.
@@ -562,39 +558,17 @@ doFold FoldOptions{..} parser conn _template q a0 f = do
562 PQ.TransUnknown -> fail "foldWithOpts FIXME: PQ.TransUnknown"
558 PQ.TransUnknown -> fail "foldWithOpts FIXME: PQ.TransUnknown"
563 -- Not sure what this means.
559 -- Not sure what this means.
565− declare = do
561+ declare =
566− name <- newTempName conn
562+ declareCursor conn q
567− _ <- execute_ conn $ mconcat
563+ fetch cursor a =
568− [ "DECLARE ", name, " NO SCROLL CURSOR FOR ", q ]
564+ foldForwardWithParser cursor parser chunkSize f a
571− (execute_ conn ("CLOSE " <> name) >> return ()) `E.catch` \ex ->
572− -- Don't throw exception if CLOSE failed because the transaction is
573− -- aborted. Otherwise, it will throw away the original error.
574− unless (isFailedTransactionError ex) $ throwIO ex
576− go = bracket declare close $ \(Query name) ->
566+ go = bracket declare closeCursor $ \cursor ->
577− let q = toByteString (byteString "FETCH FORWARD "
567+ let loop a = fetch cursor a >>=
579− <> byteString " FROM "
583− result <- exec conn q
584− status <- PQ.resultStatus result
585− case status of
568+ \r -> case r of
586− PQ.TuplesOk -> do
569+ Left a -> return a
587− nrows <- PQ.ntuples result
570+ Right a -> loop a
588− ncols <- PQ.nfields result
591− let inner a row = do
592− x <- getRowWith parser row ncols conn result
594− foldM' inner a 0 (nrows - 1) >>= loop
596− _ -> throwResultError "fold" result status
597− in loop a0
571+ in loop a0
599-- FIXME: choose the Automatic chunkSize more intelligently
573-- FIXME: choose the Automatic chunkSize more intelligently
600-- One possibility is to use the type of the results, although this
574-- One possibility is to use the type of the results, although this
@@ -644,76 +618,6 @@ forEachWith_ :: RowParser r
644forEachWith_ parser conn template = foldWith_ parser conn template () . const
618forEachWith_ parser conn template = foldWith_ parser conn template () . const
645{-# INLINE forEachWith_ #-}
619{-# INLINE forEachWith_ #-}
647−forM' :: (Ord n, Num n) => n -> n -> (n -> IO a) -> IO [a]
648−forM' lo hi m = loop hi []
651− | n < lo = return as
657−foldM' :: (Ord n, Num n) => (a -> n -> IO a) -> a -> n -> n -> IO a
658−foldM' f a lo hi = loop a lo
665−{-# INLINE foldM' #-}
667−finishQueryWith :: RowParser r -> Connection -> Query -> PQ.Result -> IO [r]
668−finishQueryWith parser conn q result = do
669− status <- PQ.resultStatus result
672− throwIO $ QueryError "query: Empty query" q
674− throwIO $ QueryError "query resulted in a command response" q
676− nrows <- PQ.ntuples result
677− ncols <- PQ.nfields result
678− forM' 0 (nrows-1) $ \row ->
679− getRowWith parser row ncols conn result
681− throwIO $ QueryError "query: COPY TO is not supported" q
683− throwIO $ QueryError "query: COPY FROM is not supported" q
684− PQ.BadResponse -> throwResultError "query" result status
685− PQ.NonfatalError -> throwResultError "query" result status
686− PQ.FatalError -> throwResultError "query" result status
688−getRowWith :: RowParser r -> PQ.Row -> PQ.Column -> Connection -> PQ.Result -> IO r
689−getRowWith parser row ncols conn result = do
690− let rw = Row row result
691− let unCol (PQ.Col x) = fromIntegral x :: Int
692− okvc <- runConversion (runStateT (runReaderT (unRP parser) rw) 0) conn
694− Ok (val,col) | col == ncols -> return val
696− vals <- forM' 0 (ncols-1) $ \c -> do
697− tinfo <- getTypeInfo conn =<< PQ.ftype result c
698− v <- PQ.getvalue result row c
701− throw (ConversionFailed
702− (show (unCol ncols) ++ " values: " ++ show vals)
705− (show (unCol col) ++ " slots in target type")
706− "mismatch between number of columns to \
707− \convert and number in target type")
708− Errors [] -> throwIO $ ConversionFailed "" Nothing "" "" "unknown error"
709− Errors [x] -> throwIO x
710− Errors xs -> throwIO $ ManyErrors xs
712−ellipsis :: ByteString -> ByteString
714− | B.length bs > 15 = B.take 10 bs `B.append` "[...]"