@@ -47,7 +47,7 @@ module Database.PostgreSQL.Simple.FromField
48import Control.Applicative
48import Control.Applicative
49 ( Applicative, (<|>), (<$>), pure )
49 ( Applicative, (<|>), (<$>), pure )
50−import Control.Exception (SomeException(..), Exception)
50+import Control.Exception (Exception)
51import Data.Attoparsec.Char8 hiding (Result)
51import Data.Attoparsec.Char8 hiding (Result)
52import Data.Bits ((.&.), (.|.), shiftL)
52import Data.Bits ((.&.), (.|.), shiftL)
53import Data.ByteString (ByteString)
53import Data.ByteString (ByteString)
@@ -65,6 +65,7 @@ import Database.PostgreSQL.Simple.Internal
65import Database.PostgreSQL.Simple.BuiltinTypes
65import Database.PostgreSQL.Simple.BuiltinTypes
66import Database.PostgreSQL.Simple.Ok
66import Database.PostgreSQL.Simple.Ok
67import Database.PostgreSQL.Simple.Types (Binary(..), Null(..))
67import Database.PostgreSQL.Simple.Types (Binary(..), Null(..))
68+import Database.PostgreSQL.Simple.TypeInfo
68import Database.PostgreSQL.Simple.Time
69import Database.PostgreSQL.Simple.Time
69import Database.PostgreSQL.Simple.Arrays
70import Database.PostgreSQL.Simple.Arrays
70import qualified Database.PostgreSQL.LibPQ as PQ
71import qualified Database.PostgreSQL.LibPQ as PQ
@@ -104,10 +105,10 @@ data ResultError = Incompatible { errSQLType :: String
105instance Exception ResultError
106instance Exception ResultError
107−left :: Exception a => a -> Ok b
108+left :: Exception a => a -> Conversion b
108−left = Errors . (:[]) . SomeException
109+left = conversionError
110−type FieldParser a = Field -> Maybe ByteString -> Ok a
111+type FieldParser a = Field -> Maybe ByteString -> Conversion a
112-- | A type that may be converted from a SQL type.
113-- | A type that may be converted from a SQL type.
113class FromField a where
114class FromField a where
@@ -137,8 +138,9 @@ class FromField a where
137-- will check a per-connection cache, and then finally query the database's
138-- will check a per-connection cache, and then finally query the database's
138-- meta-schema.
139-- meta-schema.
140−typename :: Field -> ByteString
141+typename :: Field -> Conversion ByteString
141−typename = typname . typ . typeinfo
142+typename field = Conversion $ \conn -> do
143+ Ok . typname . typ <$> getTypeInfo conn (typeOid field)
143-- | Returns the name of the column. This is often determined by a table
145-- | Returns the name of the column. This is often determined by a table
144-- definition, but it can be set using an @as@ clause.
146-- definition, but it can be set using an @as@ clause.
@@ -238,7 +240,7 @@ instance FromField LB.ByteString where
238 fromField f dat = LB.fromChunks . (:[]) <$> fromField f dat
240 fromField f dat = LB.fromChunks . (:[]) <$> fromField f dat
240unescapeBytea :: Field -> SB.ByteString
242unescapeBytea :: Field -> SB.ByteString
241− -> Ok (Binary SB.ByteString)
243+ -> Conversion (Binary SB.ByteString)
242unescapeBytea f str = case unsafePerformIO (PQ.unescapeBytea str) of
244unescapeBytea f str = case unsafePerformIO (PQ.unescapeBytea str) of
243 Nothing -> returnError ConversionFailed f "unescapeBytea failed"
245 Nothing -> returnError ConversionFailed f "unescapeBytea failed"
244 Just str -> pure (Binary str)
246 Just str -> pure (Binary str)
@@ -262,48 +264,43 @@ instance FromField [Char] where
262 fromField f dat = ST.unpack <$> fromField f dat
264 fromField f dat = ST.unpack <$> fromField f dat
264instance FromField UTCTime where
266instance FromField UTCTime where
265− fromField = ff TimestampTZ "UTCTime" parseUTCTime
267+ fromField = ff TimestampTZ parseUTCTime
267instance FromField ZonedTime where
269instance FromField ZonedTime where
268− fromField = ff TimestampTZ "ZonedTime" parseZonedTime
270+ fromField = ff TimestampTZ parseZonedTime
270instance FromField LocalTime where
272instance FromField LocalTime where
271− fromField = ff Timestamp "LocalTime" parseLocalTime
273+ fromField = ff Timestamp parseLocalTime
273instance FromField Day where
275instance FromField Day where
274− fromField = ff Date "Day" parseDay
276+ fromField = ff Date parseDay
276instance FromField TimeOfDay where
278instance FromField TimeOfDay where
277− fromField = ff Time "TimeOfDay" parseTimeOfDay
279+ fromField = ff Time parseTimeOfDay
279instance FromField UTCTimestamp where
281instance FromField UTCTimestamp where
280− fromField = ff TimestampTZ "UTCTimestamp" parseUTCTimestamp
282+ fromField = ff TimestampTZ parseUTCTimestamp
282instance FromField ZonedTimestamp where
284instance FromField ZonedTimestamp where
283− fromField = ff TimestampTZ "ZonedTimestamp" parseZonedTimestamp
285+ fromField = ff TimestampTZ parseZonedTimestamp
285instance FromField LocalTimestamp where
287instance FromField LocalTimestamp where
286− fromField = ff Timestamp "LocalTimestamp" parseLocalTimestamp
288+ fromField = ff Timestamp parseLocalTimestamp
288instance FromField Date where
290instance FromField Date where
289− fromField = ff Date "Date" parseDate
291+ fromField = ff Date parseDate
291−ff :: BuiltinType -> String -> (B8.ByteString -> Either String a)
294+ => BuiltinType -> (B8.ByteString -> Either String a)
292− -> Field -> Maybe B8.ByteString -> Ok a
295+ -> Field -> Maybe B8.ByteString -> Conversion a
293−ff pgType hsType parse f mstr =
296+ff pgType parse f mstr =
294 if typeOid f /= builtin2oid pgType
297 if typeOid f /= builtin2oid pgType
295− then err Incompatible ""
298+ then returnError Incompatible f ""
296 else case mstr of
299 else case mstr of
297− Nothing -> err UnexpectedNull ""
300+ Nothing -> returnError UnexpectedNull f ""
298 Just str -> case parse str of
301 Just str -> case parse str of
299− Left msg -> err ConversionFailed msg
302+ Left msg -> returnError ConversionFailed f msg
300 Right val -> return val
303 Right val -> return val
302− err errC msg = left $ errC (B8.unpack (typename f))
304− (maybe "" B8.unpack (name f))
307{-# INLINE ff #-}
304{-# INLINE ff #-}
309instance (FromField a, FromField b) => FromField (Either a b) where
306instance (FromField a, FromField b) => FromField (Either a b) where
@@ -315,7 +312,7 @@ instance (FromField a, Typeable a) => FromField (Vector a) where
315 (V.fromList <$>)
312 (V.fromList <$>)
316 (parseOnly (fromArray ',' f) (maybe "" id dat))
313 (parseOnly (fromArray ',' f) (maybe "" id dat))
318−fromArray :: (FromField a) => Char -> Field -> Parser (Ok [a])
315+fromArray :: (FromField a) => Char -> Field -> Parser (Conversion [a])
319fromArray delim f = sequence . (parseIt <$>) <$> array delim
316fromArray delim f = sequence . (parseIt <$>) <$> array delim
321 fElem = f{ typeinfo = TypeInfo tElem Nothing }
318 fElem = f{ typeinfo = TypeInfo tElem Nothing }
@@ -351,8 +348,8 @@ okInt = ok64
353doFromField :: forall a . (Typeable a)
350doFromField :: forall a . (Typeable a)
354− => Field -> Compat -> (ByteString -> Ok a)
351+ => Field -> Compat -> (ByteString -> Conversion a)
355− -> Maybe ByteString -> Ok a
352+ -> Maybe ByteString -> Conversion a
356doFromField f types cvt (Just bs)
353doFromField f types cvt (Just bs)
357 | Just typ <- oid2builtin (typoid $ typ $ typeinfo f)
354 | Just typ <- oid2builtin (typoid $ typ $ typeinfo f)
358 , mkCompat typ `compat` types = cvt bs
355 , mkCompat typ `compat` types = cvt bs
@@ -366,18 +363,21 @@ doFromField f _ _ _ = returnError UnexpectedNull f ""
366-- constructor.
363-- constructor.
367returnError :: forall a err . (Typeable a, Exception err)
364returnError :: forall a err . (Typeable a, Exception err)
368 => (String -> Maybe PQ.Oid -> String -> String -> String -> err)
365 => (String -> Maybe PQ.Oid -> String -> String -> String -> err)
369− -> Field -> String -> Ok a
366+ -> Field -> String -> Conversion a
370−returnError mkErr f = left . mkErr (B.unpack (typename f))
367+returnError mkErr f msg = do
368+ typnam <- typename f
369+ left $ mkErr (B.unpack typnam)
371− (tableOid f)
370+ (tableOid f)
372− (maybe "" B.unpack (name f))
371+ (maybe "" B.unpack (name f))
373− (show (typeOf (undefined :: a)))
372+ (show (typeOf (undefined :: a)))
375atto :: forall a. (Typeable a)
375atto :: forall a. (Typeable a)
376 => Compat -> Parser a -> Field -> Maybe ByteString
376 => Compat -> Parser a -> Field -> Maybe ByteString
377− -> Ok a
377+ -> Conversion a
378atto types p0 f dat = doFromField f types (go p0) dat
378atto types p0 f dat = doFromField f types (go p0) dat
380− go :: Parser a -> ByteString -> Ok a
380+ go :: Parser a -> ByteString -> Conversion a
382 case parseOnly p s of
382 case parseOnly p s of
383 Left err -> returnError ConversionFailed f err
383 Left err -> returnError ConversionFailed f err