@@ -2,7 +2,6 @@
22{-# LANGUAGE FlexibleInstances, TypeSynonymInstances #-}
33{-# LANGUAGE PatternGuards, ScopedTypeVariables #-}
44{-# LANGUAGE RecordWildCards #-}
5−{-# LANGUAGE PolyKinds #-}
65
76{- |
87Module: Database.PostgreSQL.Simple.FromField
@@ -107,27 +106,26 @@ module Database.PostgreSQL.Simple.FromField
107106 , PQ.Oid(..)
108107 , PQ.Format(..)
109108 , pgArrayFieldParser
110− , attoFieldParser
111109
112110 , optionalField
113111 , fromJSONField
114− , fromFieldJSONByteString
115112 ) where
116113
117114#include "MachDeps.h"
118115
119−import Control.Applicative ( Const(Const), (<|>), (<$>), pure, (*>), (<*) )
116+import Control.Applicative ( (<|>), (<$>), pure, (*>), (<*) )
120117import Control.Concurrent.MVar (MVar, newMVar)
121−import Control.Exception (Exception (toException, fromException))
118+import Control.Exception (Exception)
122119import qualified Data.Aeson as JSON
120+import qualified Data.Aeson.Internal as JSON
121+import qualified Data.Aeson.Parser as JSON (value')
123122import Data.Attoparsec.ByteString.Char8 hiding (Result)
124123import Data.ByteString (ByteString)
125124import qualified Data.ByteString.Char8 as B
126−import Data.Functor.Identity (Identity(Identity))
127125import Data.Int (Int16, Int32, Int64)
128126import Data.IORef (IORef, newIORef)
129127import Data.Ratio (Ratio)
130−import Data.Time.Compat ( UTCTime, ZonedTime, LocalTime, Day, TimeOfDay, CalendarDiffTime )
128+import Data.Time ( UTCTime, ZonedTime, LocalTime, Day, TimeOfDay )
131129import Data.Typeable (Typeable, typeOf)
132130import Data.Vector (Vector)
133131import Data.Vector.Mutable (IOVector)
@@ -154,8 +152,6 @@ import qualified Data.UUID.Types as UUID
154152import Data.Scientific (Scientific)
155153import GHC.Real (infinity, notANumber)
156154
157−import qualified Data.Aeson.Types as JSON
158−
159155-- | Exception thrown if conversion from a SQL value to a Haskell
160156-- value fails.
161157data ResultError = Incompatible { errSQLType :: String
@@ -182,9 +178,7 @@ data ResultError = Incompatible { errSQLType :: String
182178 -- between metadata and actual data in a row).
183179 deriving (Eq, Show, Typeable)
184180
185−instance Exception ResultError where
186− toException = postgresqlExceptionToException
187− fromException = postgresqlExceptionFromException
181+instance Exception ResultError
188182
189183left :: Exception a => a -> Conversion b
190184left = conversionError
@@ -250,11 +244,9 @@ tableOid Field{..} = toMaybeOid (unsafeDupablePerformIO (PQ.ftable result column
250244 then Nothing
251245 else Just x
252246
253−-- | If the column has a table associated with it, this returns the
254−-- number of the associated table column. Table columns have
255−-- nonzero numbers. Zero is returned if the specified column is not
256−-- a simple reference to a table column, or when using pre-3.0
257−-- protocol. Analogous to libpq's @PQftablecol@.
247+-- | If the column has a table associated with it, this returns the number
248+-- off the associated table column. Numbering starts from 0. Analogous
249+-- to libpq's @PQftablecol@.
258250
259251tableColumn :: Field -> Int
260252tableColumn Field{..} = fromCol (unsafeDupablePerformIO (PQ.ftablecol result column))
@@ -273,12 +265,6 @@ instance FromField () where
273265 | typeOid f /= TI.voidOid = returnError Incompatible f ""
274266 | otherwise = pure ()
275267
276−instance (FromField a) => FromField (Const a b) where
277− fromField f bs = Const <$> fromField f bs
278−
279−instance (FromField a) => FromField (Identity a) where
280− fromField f bs = Identity <$> fromField f bs
281−
282268-- | For dealing with null values. Compatible with any postgresql type
283269-- compatible with type @a@. Note that the type is not checked if
284270-- the value is null, although it is inadvisable to rely on this
@@ -325,11 +311,11 @@ instance FromField Char where
325311
326312-- | int2
327313instance FromField Int16 where
328− fromField = attoFieldParser ok16 $ signed decimal
314+ fromField = atto ok16 $ signed decimal
329315
330316-- | int2, int4
331317instance FromField Int32 where
332− fromField = attoFieldParser ok32 $ signed decimal
318+ fromField = atto ok32 $ signed decimal
333319
334320#if WORD_SIZE_IN_BITS < 64
335321-- | int2, int4, and if compiled as 64-bit code, int8 as well.
@@ -339,36 +325,36 @@ instance FromField Int32 where
339325-- This library was compiled as 64-bit code.
340326#endif
341327instance FromField Int where
342− fromField = attoFieldParser okInt $ signed decimal
328+ fromField = atto okInt $ signed decimal
343329
344330-- | int2, int4, int8
345331instance FromField Int64 where
346− fromField = attoFieldParser ok64 $ signed decimal
332+ fromField = atto ok64 $ signed decimal
347333
348334-- | int2, int4, int8
349335instance FromField Integer where
350− fromField = attoFieldParser ok64 $ signed decimal
336+ fromField = atto ok64 $ signed decimal
351337
352338-- | int2, float4 (Uses attoparsec's 'double' routine, for
353339-- better accuracy convert to 'Scientific' or 'Rational' first)
354340instance FromField Float where
355− fromField = attoFieldParser ok (realToFrac <$> pg_double)
341+ fromField = atto ok (realToFrac <$> pg_double)
356342 where ok = eq TI.float4Oid \/ eq TI.int2Oid
357343
358344-- | int2, int4, float4, float8 (Uses attoparsec's 'double' routine, for
359345-- better accuracy convert to 'Scientific' or 'Rational' first)
360346instance FromField Double where
361− fromField = attoFieldParser ok pg_double
347+ fromField = atto ok pg_double
362348 where ok = eq TI.float4Oid \/ eq TI.float8Oid \/ eq TI.int2Oid \/ eq TI.int4Oid
363349
364350-- | int2, int4, int8, float4, float8, numeric
365351instance FromField (Ratio Integer) where
366− fromField = attoFieldParser ok pg_rational
352+ fromField = atto ok pg_rational
367353 where ok = eq TI.float4Oid \/ eq TI.float8Oid \/ eq TI.int2Oid \/ eq TI.int4Oid \/ eq TI.int8Oid \/ eq TI.numericOid
368354
369355-- | int2, int4, int8, float4, float8, numeric
370356instance FromField Scientific where
371− fromField = attoFieldParser ok rational
357+ fromField = atto ok rational
372358 where ok = eq TI.float4Oid \/ eq TI.float8Oid \/ eq TI.int2Oid \/ eq TI.int4Oid \/ eq TI.int8Oid \/ eq TI.numericOid
373359
374360unBinary :: Binary t -> t
@@ -396,7 +382,7 @@ instance FromField SB.ByteString where
396382
397383-- | oid
398384instance FromField PQ.Oid where
399− fromField f dat = PQ.Oid <$> attoFieldParser (== TI.oidOid) decimal f dat
385+ fromField f dat = PQ.Oid <$> atto (== TI.oidOid) decimal f dat
400386
401387-- | bytea, name, text, \"char\", bpchar, varchar, unknown
402388instance FromField LB.ByteString where
@@ -489,15 +475,6 @@ instance FromField LocalTimestamp where
489475instance FromField Date where
490476 fromField = ff TI.dateOid "Date" parseDate
491477
492−-- | interval. Requires you to configure intervalstyle as @iso_8601@.
493−--
494−-- You can configure intervalstyle on every connection with a @SET@ command,
495−-- but for better performance you may want to configure it permanently in the
496−-- file found with @SHOW config_file;@ .
497−--
498−instance FromField CalendarDiffTime where
499− fromField = ff TI.intervalOid "CalendarDiffTime" parseCalendarDiffTime
500−
501478ff :: PQ.Oid -> String -> (B8.ByteString -> Either String a)
502479 -> Field -> Maybe B8.ByteString -> Conversion a
503480ff compatOid hsType parseBS f mstr =
@@ -576,13 +553,11 @@ instance FromField UUID where
576553-- | json, jsonb
577554instance FromField JSON.Value where
578555 fromField f mbs = parseBS =<< fromFieldJSONByteString f mbs
579− where parseBS bs = case JSON.eitherDecodeStrict' bs of
556+ where parseBS bs = case parseOnly (JSON.value' <* endOfInput) bs of
580557 Left err -> returnError ConversionFailed f err
581558 Right val -> pure val
582559
583560-- | Return the JSON ByteString directly
584−--
585−-- @since 0.6.3
586561fromFieldJSONByteString :: Field -> Maybe ByteString -> Conversion ByteString
587562fromFieldJSONByteString f mbs =
588563 if typeOid f /= TI.jsonOid && typeOid f /= TI.jsonbOid
@@ -684,22 +659,10 @@ returnError mkErr f msg = do
684659 (show (typeOf (undefined :: a)))
685660 msg
686661
687−-- | Construct a field parser from an attoparsec parser. An 'Incompatible' error is thrown if the
688−-- PostgreSQL oid does not match the specified predicate.
689−--
690−-- @
691−-- instance FromField Int16 where
692−-- fromField = attoFieldParser ok16 (signed decimal)
693−-- @
694−--
695−-- @since 0.6.3
696−attoFieldParser :: forall a. (Typeable a)
697− => (PQ.Oid -> Bool)
698− -- ^ Predicate for whether the postgresql type oid is compatible with this parser
699− -> Parser a
700− -- ^ An attoparsec parser.
701− -> FieldParser a
702−attoFieldParser types p0 f dat = doFromField f types (go p0) dat
662+atto :: forall a. (Typeable a)
663+ => Compat -> Parser a -> Field -> Maybe ByteString
664+ -> Conversion a
665+atto types p0 f dat = doFromField f types (go p0) dat
703666 where
704667 go :: Parser a -> ByteString -> Conversion a
705668 go p s =