git.iko.soy/typeable/postgresql-simple
on master help sign in
Handle NaN and ±Infinity

Closes #121

commit12e43e458bc17b0c4f01000c95133f2b5eca7c4e authorLeon P Smith <leon@melding-monads.com> dateTue 23 Sep 2014, 14:02 (12 years ago) parentb8fd9c2
2 files changed+30−4
src/Database/PostgreSQL/Simple/FromField.hs+19−4 test/Main.hs+11
src/Database/PostgreSQL/Simple/FromField.hs+19−4
@@ -104,7 +104,7 @@ module Database.PostgreSQL.Simple.FromField
104104
105105#include "MachDeps.h"
106106
107−import Control.Applicative ( (<|>), (<$>), pure )
107+import Control.Applicative ( (<|>), (<$>), pure, (*>) )
108108import Control.Concurrent.MVar (MVar, newMVar)
109109import Control.Exception (Exception)
110110import qualified Data.Aeson as JSON
@@ -138,6 +138,7 @@ import qualified Data.Text.Lazy as LT
138138import Data.UUID (UUID)
139139import qualified Data.UUID as UUID
140140import Data.Scientific (Scientific)
141+import GHC.Real (infinity, notANumber)
141142
142143-- | Exception thrown if conversion from a SQL value to a Haskell
143144-- value fails.
@@ -314,18 +315,18 @@ instance FromField Integer where
314315-- | int2, float4 (Uses attoparsec's 'double' routine, for
315316-- better accuracy convert to 'Scientific' or 'Rational' first)
316317instance FromField Float where
317− fromField = atto ok (realToFrac <$> double)
318+ fromField = atto ok (realToFrac <$> pg_double)
318319 where ok = $(mkCompats [TI.float4,TI.int2])
319320
320321-- | int2, int4, float4, float8 (Uses attoparsec's 'double' routine, for
321322-- better accuracy convert to 'Scientific' or 'Rational' first)
322323instance FromField Double where
323− fromField = atto ok double
324+ fromField = atto ok pg_double
324325 where ok = $(mkCompats [TI.float4,TI.float8,TI.int2,TI.int4])
325326
326327-- | int2, int4, float4, float8, numeric
327328instance FromField (Ratio Integer) where
328− fromField = atto ok rational
329+ fromField = atto ok pg_rational
329330 where ok = $(mkCompats [TI.float4,TI.float8,TI.int2,TI.int4,TI.numeric])
330331
331332-- | int2, int4, float4, float8, numeric
@@ -336,6 +337,20 @@ instance FromField Scientific where
336337unBinary :: Binary t -> t
337338unBinary (Binary x) = x
338339
340+pg_double :: Parser Double
341+pg_double
342+ = (string "NaN" *> pure ( 0 / 0))
343+ <|> (string "Infinity" *> pure ( 1 / 0))
344+ <|> (string "-Infinity" *> pure (-1 / 0))
345+ <|> double
346+
347+pg_rational :: Parser Rational
348+pg_rational
349+ = (string "NaN" *> pure notANumber )
350+ <|> (string "Infinity" *> pure infinity )
351+ <|> (string "-Infinity" *> pure (-infinity))
352+ <|> rational
353+
339354-- | bytea, name, text, \"char\", bpchar, varchar, unknown
340355instance FromField SB.ByteString where
341356 fromField f dat = if typeOid f == $(inlineTypoid TI.bytea)
test/Main.hs+11
@@ -43,6 +43,7 @@ tests =
4343 , TestLabel "Unicode" . testUnicode
4444 , TestLabel "Values" . testValues
4545 , TestLabel "Copy" . testCopy
46+ , TestLabel "Double" . testDouble
4647 ]
4748
4849testBytea :: TestEnv -> Test
@@ -306,6 +307,16 @@ testCopy TestEnv{..} = TestCase $ do
306307 CopyOutDone _ -> return rows
307308 CopyOutRow row -> loop (row:rows)
308309
310+testDouble :: TestEnv -> Test
311+testDouble TestEnv{..} = TestCase $ do
312+ [Only (x :: Double)] <- query_ conn "SELECT 'NaN'::float8"
313+ assertBool "expected NaN" (isNaN x)
314+ [Only (x :: Double)] <- query_ conn "SELECT 'Infinity'::float8"
315+ x @?= (1 / 0)
316+ [Only (x :: Double)] <- query_ conn "SELECT '-Infinity'::float8"
317+ x @?= (-1 / 0)
318+
319+
309320data TestException
310321 = TestException
311322 deriving (Eq, Show, Typeable)