module Database.HDBC.Statement
(
Statement(..),
SqlError(..),
SqlType(..), nToSql, iToSql,
SqlValue(..)
)
where
import Data.Dynamic
import qualified Data.ByteString as B
import Data.Char(ord,toUpper)
import Data.Word
import Data.Int
import System.Time
import Database.HDBC.ColTypes
data Statement = Statement
{
execute :: [SqlValue] -> IO Integer,
executeMany :: [[SqlValue]] -> IO (),
finish :: IO (),
fetchRow :: IO (Maybe [SqlValue]),
getColumnNames :: IO [String],
originalQuery :: String,
describeResult :: IO [(String, SqlColDesc)]
}
data SqlError = SqlError {seState :: String,
seNativeError :: Int,
seErrorMsg :: String}
deriving (Eq, Show, Read)
sqlErrorTc :: TyCon
sqlErrorTc = mkTyCon "Database.HDBC.SqlError"
instance Typeable SqlError where
typeOf _ = mkTyConApp sqlErrorTc []
class (Show a) => SqlType a where
toSql :: a -> SqlValue
fromSql :: SqlValue -> a
nToSql :: Integral a => a -> SqlValue
nToSql n = SqlInteger (toInteger n)
iToSql :: Int -> SqlValue
iToSql = toSql
data SqlValue = SqlString String
| SqlByteString B.ByteString
| SqlWord32 Word32
| SqlWord64 Word64
| SqlInt32 Int32
| SqlInt64 Int64
| SqlInteger Integer
| SqlChar Char
| SqlBool Bool
| SqlDouble Double
| SqlRational Rational
| SqlEpochTime Integer
| SqlTimeDiff Integer
| SqlNull
deriving (Show)
instance Eq SqlValue where
SqlString a == SqlString b = a == b
SqlByteString a == SqlByteString b = a == b
SqlWord32 a == SqlWord32 b = a == b
SqlWord64 a == SqlWord64 b = a == b
SqlInt32 a == SqlInt32 b = a == b
SqlInt64 a == SqlInt64 b = a == b
SqlInteger a == SqlInteger b = a == b
SqlChar a == SqlChar b = a == b
SqlBool a == SqlBool b = a == b
SqlDouble a == SqlDouble b = a == b
SqlRational a == SqlRational b = a == b
SqlEpochTime a == SqlEpochTime b = a == b
SqlTimeDiff a == SqlTimeDiff b = a == b
SqlNull == SqlNull = True
SqlNull == _ = False
_ == SqlNull = False
a == b = ((fromSql a)::String) == ((fromSql b)::String)
instance SqlType String where
toSql = SqlString
fromSql (SqlString x) = x
fromSql (SqlByteString x) = byteString2String x
fromSql (SqlInt32 x) = show x
fromSql (SqlInt64 x) = show x
fromSql (SqlWord32 x) = show x
fromSql (SqlWord64 x) = show x
fromSql (SqlInteger x) = show x
fromSql (SqlChar x) = [x]
fromSql (SqlBool x) = show x
fromSql (SqlDouble x) = show x
fromSql (SqlRational x) = show x
fromSql (SqlEpochTime x) = show x
fromSql (SqlTimeDiff x) = show x
fromSql (SqlNull) = error "fromSql: cannot convert SqlNull to String"
instance SqlType B.ByteString where
toSql = SqlByteString
fromSql (SqlByteString x) = x
fromSql (SqlNull) = error "fromSql: cannot convert SqlNull to ByteString"
fromSql x = (string2ByteString . fromSql) x
string2ByteString :: String -> B.ByteString
string2ByteString = B.pack . map (toEnum . fromEnum)
instance SqlType Int where
toSql x = SqlInt32 (fromIntegral x)
fromSql (SqlString x) = read' x
fromSql (SqlByteString x) = (read' . byteString2String) x
fromSql (SqlInt32 x) = fromIntegral x
fromSql (SqlInt64 x) = fromIntegral x
fromSql (SqlWord32 x) = fromIntegral x
fromSql (SqlWord64 x) = fromIntegral x
fromSql (SqlInteger x) = fromIntegral x
fromSql (SqlChar x) = ord x
fromSql (SqlBool x) = if x then 1 else 0
fromSql (SqlDouble x) = truncate $ x
fromSql (SqlRational x) = truncate $ x
fromSql (SqlEpochTime x) = fromIntegral x
fromSql (SqlTimeDiff x) = fromIntegral x
fromSql (SqlNull) = error "fromSql: cannot convert SqlNull to Int"
instance SqlType Int32 where
toSql = SqlInt32
fromSql (SqlString x) = read' x
fromSql (SqlByteString x) = (read' . byteString2String) x
fromSql (SqlInt32 x) = x
fromSql (SqlInt64 x) = fromIntegral x
fromSql (SqlWord32 x) = fromIntegral x
fromSql (SqlWord64 x) = fromIntegral x
fromSql (SqlInteger x) = fromIntegral x
fromSql (SqlChar x) = fromIntegral $ ord x
fromSql (SqlBool x) = if x then 1 else 0
fromSql (SqlDouble x) = truncate $ x
fromSql (SqlRational x) = truncate $ x
fromSql (SqlEpochTime x) = fromIntegral x
fromSql (SqlTimeDiff x) = fromIntegral x
fromSql (SqlNull) = error "fromSql: cannot convert SqlNull to Int32"
instance SqlType Int64 where
toSql = SqlInt64
fromSql (SqlString x) = read' x
fromSql (SqlByteString x) = (read' . byteString2String) x
fromSql (SqlInt32 x) = fromIntegral x
fromSql (SqlInt64 x) = x
fromSql (SqlWord32 x) = fromIntegral x
fromSql (SqlWord64 x) = fromIntegral x
fromSql (SqlInteger x) = fromIntegral x
fromSql (SqlChar x) = fromIntegral $ ord x
fromSql (SqlBool x) = if x then 1 else 0
fromSql (SqlDouble x) = truncate $ x
fromSql (SqlRational x) = truncate $ x
fromSql (SqlEpochTime x) = fromIntegral x
fromSql (SqlTimeDiff x) = fromIntegral x
fromSql (SqlNull) = error "fromSql: cannot convert SqlNull to Int64"
instance SqlType Word32 where
toSql = SqlWord32
fromSql (SqlString x) = read' x
fromSql (SqlByteString x) = (read' . byteString2String) x
fromSql (SqlInt32 x) = fromIntegral x
fromSql (SqlInt64 x) = fromIntegral x
fromSql (SqlWord32 x) = x
fromSql (SqlWord64 x) = fromIntegral x
fromSql (SqlInteger x) = fromIntegral x
fromSql (SqlChar x) = fromIntegral $ ord x
fromSql (SqlBool x) = if x then 1 else 0
fromSql (SqlDouble x) = truncate $ x
fromSql (SqlRational x) = truncate $ x
fromSql (SqlEpochTime x) = fromIntegral x
fromSql (SqlTimeDiff x) = fromIntegral x
fromSql (SqlNull) = error "fromSql: cannot convert SqlNull to Word32"
instance SqlType Word64 where
toSql = SqlWord64
fromSql (SqlString x) = read' x
fromSql (SqlByteString x) = (read' . byteString2String) x
fromSql (SqlInt32 x) = fromIntegral x
fromSql (SqlInt64 x) = fromIntegral x
fromSql (SqlWord32 x) = fromIntegral x
fromSql (SqlWord64 x) = x
fromSql (SqlInteger x) = fromIntegral x
fromSql (SqlChar x) = fromIntegral (ord x)
fromSql (SqlBool x) = if x then 1 else 0
fromSql (SqlDouble x) = truncate $ x
fromSql (SqlRational x) = truncate $ x
fromSql (SqlEpochTime x) = fromIntegral x
fromSql (SqlTimeDiff x) = fromIntegral x
fromSql (SqlNull) = error "fromSql: cannot convert SqlNull to Int64"
instance SqlType Integer where
toSql = SqlInteger
fromSql (SqlString x) = read' x
fromSql (SqlByteString x) = (read' . byteString2String) x
fromSql (SqlInt32 x) = fromIntegral x
fromSql (SqlInt64 x) = fromIntegral x
fromSql (SqlWord32 x) = fromIntegral x
fromSql (SqlWord64 x) = fromIntegral x
fromSql (SqlInteger x) = x
fromSql (SqlChar x) = fromIntegral (ord x)
fromSql (SqlBool x) = if x then 1 else 0
fromSql (SqlDouble x) = truncate $ x
fromSql (SqlRational x) = truncate $ x
fromSql (SqlEpochTime x) = x
fromSql (SqlTimeDiff x) = x
fromSql (SqlNull) = error "fromSql: cannot convert SqlNull to Integer"
instance SqlType Bool where
toSql = SqlBool
fromSql (SqlString x) =
case map toUpper x of
"TRUE" -> True
"T" -> True
"FALSE" -> False
"F" -> False
_ -> error $ "fromSql: cannot convert SqlString "
++ show x ++ " to Bool"
fromSql (SqlByteString x) = (fromSql . SqlString . byteString2String) x
fromSql (SqlInt32 x) = numToBool x
fromSql (SqlInt64 x) = numToBool x
fromSql (SqlWord32 x) = numToBool x
fromSql (SqlWord64 x) = numToBool x
fromSql (SqlInteger x) = numToBool x
fromSql (SqlChar x) = numToBool (ord x)
fromSql (SqlBool x) = x
fromSql (SqlDouble x) = numToBool x
fromSql (SqlRational x) = numToBool x
fromSql (SqlEpochTime x) = numToBool x
fromSql (SqlTimeDiff x) = numToBool x
fromSql (SqlNull) = error "fromSql: cannot convert SqlNull to Bool"
numToBool :: Num a => a -> Bool
numToBool x = x /= 0
instance SqlType Char where
toSql = SqlChar
fromSql (SqlString [x]) = x
fromSql (SqlByteString x) = (head . byteString2String) x
fromSql (SqlString _) = error "fromSql: cannot convert SqlString to Char"
fromSql (SqlInt32 _) = error "fromSql: cannot convert SqlInt32 to Char"
fromSql (SqlInt64 _) = error "fromSql: cannot convert SqlInt64 to Char"
fromSql (SqlWord32 _) = error "fromSql: cannot convert SqlWord32 to Char"
fromSql (SqlWord64 _) = error "fromSql: cannot convert SqlWord64 to Char"
fromSql (SqlInteger _) = error "fromSql: cannot convert SqlInt to Char"
fromSql (SqlChar x) = x
fromSql (SqlBool x) = if x then '1' else '0'
fromSql (SqlDouble _) = error "fromSql: cannot convert SqlDouble to Char"
fromSql (SqlRational _) = error "fromSql: cannot convert SqlRational to Char"
fromSql (SqlEpochTime _) = error "fromSql: cannot convert SqlEpochTime to Char"
fromSql (SqlTimeDiff _) = error "fromSql: cannot convert SqlTimeDiff to Char"
fromSql (SqlNull) = error "fromSql: cannot convert SqlNull to Char"
instance SqlType Double where
toSql = SqlDouble
fromSql (SqlString x) = read' x
fromSql (SqlByteString x) = (read' . byteString2String) x
fromSql (SqlInt32 x) = fromIntegral x
fromSql (SqlInt64 x) = fromIntegral x
fromSql (SqlWord32 x) = fromIntegral x
fromSql (SqlWord64 x) = fromIntegral x
fromSql (SqlInteger x) = fromIntegral x
fromSql (SqlChar x) = fromIntegral . ord $ x
fromSql (SqlBool x) = if x then 1.0 else 0.0
fromSql (SqlDouble x) = x
fromSql (SqlRational x) = fromRational x
fromSql (SqlEpochTime x) = fromIntegral x
fromSql (SqlTimeDiff x) = fromIntegral x
fromSql (SqlNull) = error "fromSql: cannot convert SqlNull to Double"
instance SqlType Rational where
toSql = SqlRational
fromSql (SqlString x) = read' x
fromSql (SqlByteString x) = (read' . byteString2String) x
fromSql (SqlInt32 x) = fromIntegral x
fromSql (SqlInt64 x) = fromIntegral x
fromSql (SqlWord32 x) = fromIntegral x
fromSql (SqlWord64 x) = fromIntegral x
fromSql (SqlInteger x) = fromIntegral x
fromSql (SqlChar x) = fromIntegral . ord $ x
fromSql (SqlBool x) = fromIntegral $ ((fromSql (SqlBool x))::Int)
fromSql (SqlDouble x) = toRational x
fromSql (SqlRational x) = x
fromSql (SqlEpochTime x) = fromIntegral x
fromSql (SqlTimeDiff x) = fromIntegral x
fromSql (SqlNull) = error "fromSql: cannot convert SqlNull to Double"
instance SqlType ClockTime where
toSql (TOD x _) = SqlEpochTime x
fromSql (SqlString x) = TOD (read' x) 0
fromSql (SqlByteString x) = TOD ((read' . byteString2String) x) 0
fromSql (SqlInt32 x) = TOD (fromIntegral x) 0
fromSql (SqlInt64 x) = TOD (fromIntegral x) 0
fromSql (SqlWord32 x) = TOD (fromIntegral x) 0
fromSql (SqlWord64 x) = TOD (fromIntegral x) 0
fromSql (SqlInteger x) = TOD x 0
fromSql (SqlChar _) = error "fromSql: cannot convert SqlChar to ClockTime"
fromSql (SqlBool _) = error "fromSql: cannot convert SqlBool to ClockTime"
fromSql (SqlDouble x) = TOD (truncate x) 0
fromSql (SqlRational x) = TOD (truncate x) 0
fromSql (SqlEpochTime x) = TOD x 0
fromSql (SqlTimeDiff _) = error "fromSql: cannot convert SqlTimeDiff to ClockTime"
fromSql SqlNull = error "fromSql: cannot convert SqlNull to ClockTime"
instance SqlType TimeDiff where
toSql x = SqlTimeDiff (timeDiffToSecs x)
fromSql (SqlString x) = secs2td (read' x)
fromSql (SqlByteString x) = secs2td ((read' . byteString2String) x)
fromSql (SqlInt32 x) = secs2td (fromIntegral x)
fromSql (SqlInt64 x) = secs2td (fromIntegral x)
fromSql (SqlWord32 x) = secs2td (fromIntegral x)
fromSql (SqlWord64 x) = secs2td (fromIntegral x)
fromSql (SqlInteger x) = secs2td x
fromSql (SqlChar _) = error "fromSql: cannot convert SqlChar to TimeDiff"
fromSql (SqlBool _) = error "fromSql: cannot convert SqlBool to TimeDiff"
fromSql (SqlDouble x) = secs2td (truncate x)
fromSql (SqlRational x) = secs2td (truncate x)
fromSql (SqlEpochTime _) = error "fromSql: cannot convert SqlEpochTime to TimeDiff"
fromSql (SqlTimeDiff x) = secs2td x
fromSql SqlNull = error "fromSql: cannot convert SqlNull to TimeDiff"
instance SqlType CalendarTime where
toSql x = toSql (toClockTime x)
fromSql = toUTCTime . fromSql
instance (SqlType a) => SqlType (Maybe a) where
toSql Nothing = SqlNull
toSql (Just a) = toSql a
fromSql SqlNull = Nothing
fromSql x = Just (fromSql x)
byteString2String :: B.ByteString -> String
byteString2String = map (toEnum . fromEnum) . B.unpack
secs2td :: Integer -> TimeDiff
secs2td x = diffClockTimes (TOD x 0) (TOD 0 0)
read' :: (Typeable a,Read a) => String -> a
read' s = ret
where ret = case reads s of
[(x,"")] -> x
_ -> error $ "fromSql: Cannot read " ++ show s
++ " as " ++ t ++ "."
t = show (typeOf ret)
timeDiffToSecs :: TimeDiff -> Integer
timeDiffToSecs td =
(fromIntegral $ tdSec td) +
60 * ((fromIntegral $ tdMin td) +
60 * ((fromIntegral $ tdHour td) +
24 * ((fromIntegral $ tdDay td) +
30 * ((fromIntegral $ tdMonth td) +
365 * (fromIntegral $ tdYear td)))))