@@ -47,7 +47,7 @@ module Database.PostgreSQL.Simple.FromField
4747
4848import Control.Applicative
4949 ( Applicative, (<|>), (<$>), pure )
50−import Control.Exception (SomeException(..), Exception)
50+import Control.Exception (Exception)
5151import Data.Attoparsec.Char8 hiding (Result)
5252import Data.Bits ((.&.), (.|.), shiftL)
5353import Data.ByteString (ByteString)
@@ -65,6 +65,7 @@ import Database.PostgreSQL.Simple.Internal
6565import Database.PostgreSQL.Simple.BuiltinTypes
6666import Database.PostgreSQL.Simple.Ok
6767import Database.PostgreSQL.Simple.Types (Binary(..), Null(..))
68+import Database.PostgreSQL.Simple.TypeInfo
6869import Database.PostgreSQL.Simple.Time
6970import Database.PostgreSQL.Simple.Arrays
7071import qualified Database.PostgreSQL.LibPQ as PQ
@@ -104,10 +105,10 @@ data ResultError = Incompatible { errSQLType :: String
104105
105106instance Exception ResultError
106107
107−left :: Exception a => a -> Ok b
108−left = Errors . (:[]) . SomeException
108+left :: Exception a => a -> Conversion b
109+left = conversionError
109110
110−type FieldParser a = Field -> Maybe ByteString -> Ok a
111+type FieldParser a = Field -> Maybe ByteString -> Conversion a
111112
112113-- | A type that may be converted from a SQL type.
113114class FromField a where
@@ -137,8 +138,9 @@ class FromField a where
137138-- will check a per-connection cache, and then finally query the database's
138139-- meta-schema.
139140
140−typename :: Field -> ByteString
141−typename = typname . typ . typeinfo
141+typename :: Field -> Conversion ByteString
142+typename field = Conversion $ \conn -> do
143+ Ok . typname . typ <$> getTypeInfo conn (typeOid field)
142144
143145-- | Returns the name of the column. This is often determined by a table
144146-- definition, but it can be set using an @as@ clause.
@@ -238,7 +240,7 @@ instance FromField LB.ByteString where
238240 fromField f dat = LB.fromChunks . (:[]) <$> fromField f dat
239241
240242unescapeBytea :: Field -> SB.ByteString
241− -> Ok (Binary SB.ByteString)
243+ -> Conversion (Binary SB.ByteString)
242244unescapeBytea f str = case unsafePerformIO (PQ.unescapeBytea str) of
243245 Nothing -> returnError ConversionFailed f "unescapeBytea failed"
244246 Just str -> pure (Binary str)
@@ -262,48 +264,43 @@ instance FromField [Char] where
262264 fromField f dat = ST.unpack <$> fromField f dat
263265
264266instance FromField UTCTime where
265− fromField = ff TimestampTZ "UTCTime" parseUTCTime
267+ fromField = ff TimestampTZ parseUTCTime
266268
267269instance FromField ZonedTime where
268− fromField = ff TimestampTZ "ZonedTime" parseZonedTime
270+ fromField = ff TimestampTZ parseZonedTime
269271
270272instance FromField LocalTime where
271− fromField = ff Timestamp "LocalTime" parseLocalTime
273+ fromField = ff Timestamp parseLocalTime
272274
273275instance FromField Day where
274− fromField = ff Date "Day" parseDay
276+ fromField = ff Date parseDay
275277
276278instance FromField TimeOfDay where
277− fromField = ff Time "TimeOfDay" parseTimeOfDay
279+ fromField = ff Time parseTimeOfDay
278280
279281instance FromField UTCTimestamp where
280− fromField = ff TimestampTZ "UTCTimestamp" parseUTCTimestamp
282+ fromField = ff TimestampTZ parseUTCTimestamp
281283
282284instance FromField ZonedTimestamp where
283− fromField = ff TimestampTZ "ZonedTimestamp" parseZonedTimestamp
285+ fromField = ff TimestampTZ parseZonedTimestamp
284286
285287instance FromField LocalTimestamp where
286− fromField = ff Timestamp "LocalTimestamp" parseLocalTimestamp
288+ fromField = ff Timestamp parseLocalTimestamp
287289
288290instance FromField Date where
289− fromField = ff Date "Date" parseDate
291+ fromField = ff Date parseDate
290292
291−ff :: BuiltinType -> String -> (B8.ByteString -> Either String a)
292− -> Field -> Maybe B8.ByteString -> Ok a
293−ff pgType hsType parse f mstr =
293+ff :: Typeable a
294+ => BuiltinType -> (B8.ByteString -> Either String a)
295+ -> Field -> Maybe B8.ByteString -> Conversion a
296+ff pgType parse f mstr =
294297 if typeOid f /= builtin2oid pgType
295− then err Incompatible ""
298+ then returnError Incompatible f ""
296299 else case mstr of
297− Nothing -> err UnexpectedNull ""
300+ Nothing -> returnError UnexpectedNull f ""
298301 Just str -> case parse str of
299− Left msg -> err ConversionFailed msg
302+ Left msg -> returnError ConversionFailed f msg
300303 Right val -> return val
301− where
302− err errC msg = left $ errC (B8.unpack (typename f))
303− (tableOid f)
304− (maybe "" B8.unpack (name f))
305− hsType
306− msg
307304{-# INLINE ff #-}
308305
309306instance (FromField a, FromField b) => FromField (Either a b) where
@@ -315,7 +312,7 @@ instance (FromField a, Typeable a) => FromField (Vector a) where
315312 (V.fromList <$>)
316313 (parseOnly (fromArray ',' f) (maybe "" id dat))
317314
318−fromArray :: (FromField a) => Char -> Field -> Parser (Ok [a])
315+fromArray :: (FromField a) => Char -> Field -> Parser (Conversion [a])
319316fromArray delim f = sequence . (parseIt <$>) <$> array delim
320317 where
321318 fElem = f{ typeinfo = TypeInfo tElem Nothing }
@@ -351,8 +348,8 @@ okInt = ok64
351348#endif
352349
353350doFromField :: forall a . (Typeable a)
354− => Field -> Compat -> (ByteString -> Ok a)
355− -> Maybe ByteString -> Ok a
351+ => Field -> Compat -> (ByteString -> Conversion a)
352+ -> Maybe ByteString -> Conversion a
356353doFromField f types cvt (Just bs)
357354 | Just typ <- oid2builtin (typoid $ typ $ typeinfo f)
358355 , mkCompat typ `compat` types = cvt bs
@@ -366,18 +363,21 @@ doFromField f _ _ _ = returnError UnexpectedNull f ""
366363-- constructor.
367364returnError :: forall a err . (Typeable a, Exception err)
368365 => (String -> Maybe PQ.Oid -> String -> String -> String -> err)
369− -> Field -> String -> Ok a
370−returnError mkErr f = left . mkErr (B.unpack (typename f))
371− (tableOid f)
372− (maybe "" B.unpack (name f))
373− (show (typeOf (undefined :: a)))
366+ -> Field -> String -> Conversion a
367+returnError mkErr f msg = do
368+ typnam <- typename f
369+ left $ mkErr (B.unpack typnam)
370+ (tableOid f)
371+ (maybe "" B.unpack (name f))
372+ (show (typeOf (undefined :: a)))
373+ msg
374374
375375atto :: forall a. (Typeable a)
376376 => Compat -> Parser a -> Field -> Maybe ByteString
377− -> Ok a
377+ -> Conversion a
378378atto types p0 f dat = doFromField f types (go p0) dat
379379 where
380− go :: Parser a -> ByteString -> Ok a
380+ go :: Parser a -> ByteString -> Conversion a
381381 go p s =
382382 case parseOnly p s of
383383 Left err -> returnError ConversionFailed f err