From 0fab8f8605528f5a9fd87dd4276843ba1e681fdf Mon Sep 17 00:00:00 2001 From: Rick Owens Date: Wed, 1 Aug 2018 15:34:26 -0500 Subject: [PATCH] Format `SqlRational` as a decimal ... ... in order to avoid this error when trying to insert a rational value into the database: SqlError {seState = "22P02", seNativeError = 7, seErrorMsg = "execute: PGRES_FATAL_ERROR: ERROR: invalid input syntax for type numeric: \"603 % 10\"\n"} Apparently, the `Show` instance isn't good enough. This implementation technically losses some precision in some cases, but then Haskell's `Rational` is larger than PostgreSQL's `numeric`, so that is fundamentally unavoidable. --- Database/HDBC/PostgreSQL/Utils.hsc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Database/HDBC/PostgreSQL/Utils.hsc b/Database/HDBC/PostgreSQL/Utils.hsc index 752f823..18731fc 100644 --- a/Database/HDBC/PostgreSQL/Utils.hsc +++ b/Database/HDBC/PostgreSQL/Utils.hsc @@ -15,6 +15,7 @@ import Foreign.Storable import Foreign.Marshal.Array import Foreign.Marshal.Alloc import Foreign.Marshal.Utils +import Data.Fixed (Pico, showFixed) import Data.Word import qualified Data.ByteString.UTF8 as BUTF8 import qualified Data.ByteString as B @@ -76,12 +77,19 @@ withCStringArr0 inp action = withAnyArr0 convfunc freefunc inp action convfunc y@(SqlUTCTime _) = convfunc (SqlZonedTime (fromSql y)) convfunc y@(SqlEpochTime _) = convfunc (SqlZonedTime (fromSql y)) convfunc (SqlByteString x) = cstrUtf8BString (cleanUpBSNulls x) + convfunc (SqlRational rat) = cstrUtf8BString (showRational rat) convfunc x = cstrUtf8BString (fromSql x) freefunc x = if x == nullPtr then return () else free x + +{- | Helper that formats a 'Rational' using decimal. -} +showRational :: Rational -> B.ByteString +showRational rat = BCHAR8.pack $ showFixed True (fromRational rat :: Pico) + + cleanUpBSNulls :: B.ByteString -> B.ByteString cleanUpBSNulls bs | 0 `B.notElem` bs = bs | otherwise = B.concatMap convfunc bs