hsql 1.7.1 → 1.8.1
raw patch · 13 files changed
+982/−748 lines, 13 filesdep ~basenew-uploaderPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base
API changes (from Hackage documentation)
- Database.HSQL: fromSqlValue :: (SqlBind a) => SqlType -> String -> Maybe a
- Database.HSQL: instance (SqlBind a) => SqlBind (Maybe a)
- Database.HSQL: instance Eq Box
- Database.HSQL: instance Eq Circle
- Database.HSQL: instance Eq INetAddr
- Database.HSQL: instance Eq Line
- Database.HSQL: instance Eq MacAddr
- Database.HSQL: instance Eq Path
- Database.HSQL: instance Eq Point
- Database.HSQL: instance Eq Polygon
- Database.HSQL: instance Show Box
- Database.HSQL: instance Show Circle
- Database.HSQL: instance Show INetAddr
- Database.HSQL: instance Show Line
- Database.HSQL: instance Show MacAddr
- Database.HSQL: instance Show Path
- Database.HSQL: instance Show Point
- Database.HSQL: instance Show Polygon
- Database.HSQL: instance SqlBind Bool
- Database.HSQL: instance SqlBind Box
- Database.HSQL: instance SqlBind Circle
- Database.HSQL: instance SqlBind ClockTime
- Database.HSQL: instance SqlBind Double
- Database.HSQL: instance SqlBind Float
- Database.HSQL: instance SqlBind INetAddr
- Database.HSQL: instance SqlBind Int
- Database.HSQL: instance SqlBind Int64
- Database.HSQL: instance SqlBind Integer
- Database.HSQL: instance SqlBind Line
- Database.HSQL: instance SqlBind MacAddr
- Database.HSQL: instance SqlBind Path
- Database.HSQL: instance SqlBind Point
- Database.HSQL: instance SqlBind Polygon
- Database.HSQL: instance SqlBind String
- Database.HSQL: toSqlValue :: (SqlBind a) => a -> String
- Database.HSQL.Types: Connection :: IO () -> (String -> IO ()) -> (String -> IO Statement) -> IO [String] -> (String -> IO [FieldDef]) -> IO () -> IO () -> IO () -> MVar Bool -> Connection
- Database.HSQL.Types: SqlAbsTime :: SqlType
- Database.HSQL.Types: SqlAbsTimeInterval :: SqlType
- Database.HSQL.Types: SqlBLOB :: SqlType
- Database.HSQL.Types: SqlBadTypeCast :: String -> SqlType -> SqlError
- Database.HSQL.Types: SqlBigInt :: SqlType
- Database.HSQL.Types: SqlBinary :: Int -> SqlType
- Database.HSQL.Types: SqlBit :: SqlType
- Database.HSQL.Types: SqlBox :: SqlType
- Database.HSQL.Types: SqlCIDRAddr :: SqlType
- Database.HSQL.Types: SqlChar :: Int -> SqlType
- Database.HSQL.Types: SqlCircle :: SqlType
- Database.HSQL.Types: SqlClosedHandle :: SqlError
- Database.HSQL.Types: SqlDate :: SqlType
- Database.HSQL.Types: SqlDateTime :: SqlType
- Database.HSQL.Types: SqlDateTimeTZ :: SqlType
- Database.HSQL.Types: SqlDecimal :: Int -> Int -> SqlType
- Database.HSQL.Types: SqlDouble :: SqlType
- Database.HSQL.Types: SqlENUM :: SqlType
- Database.HSQL.Types: SqlError :: String -> Int -> String -> SqlError
- Database.HSQL.Types: SqlFetchNull :: String -> SqlError
- Database.HSQL.Types: SqlFloat :: SqlType
- Database.HSQL.Types: SqlINetAddr :: SqlType
- Database.HSQL.Types: SqlInteger :: SqlType
- Database.HSQL.Types: SqlInvalidHandle :: SqlError
- Database.HSQL.Types: SqlLSeg :: SqlType
- Database.HSQL.Types: SqlLine :: SqlType
- Database.HSQL.Types: SqlLongVarBinary :: Int -> SqlType
- Database.HSQL.Types: SqlLongVarChar :: Int -> SqlType
- Database.HSQL.Types: SqlMacAddr :: SqlType
- Database.HSQL.Types: SqlMedInt :: SqlType
- Database.HSQL.Types: SqlMoney :: SqlType
- Database.HSQL.Types: SqlNeedData :: SqlError
- Database.HSQL.Types: SqlNoData :: SqlError
- Database.HSQL.Types: SqlNumeric :: Int -> Int -> SqlType
- Database.HSQL.Types: SqlPath :: SqlType
- Database.HSQL.Types: SqlPoint :: SqlType
- Database.HSQL.Types: SqlPolygon :: SqlType
- Database.HSQL.Types: SqlReal :: SqlType
- Database.HSQL.Types: SqlRelTime :: SqlType
- Database.HSQL.Types: SqlSET :: SqlType
- Database.HSQL.Types: SqlSmallInt :: SqlType
- Database.HSQL.Types: SqlStillExecuting :: SqlError
- Database.HSQL.Types: SqlText :: SqlType
- Database.HSQL.Types: SqlTime :: SqlType
- Database.HSQL.Types: SqlTimeInterval :: SqlType
- Database.HSQL.Types: SqlTimeStamp :: SqlType
- Database.HSQL.Types: SqlTimeTZ :: SqlType
- Database.HSQL.Types: SqlTinyInt :: SqlType
- Database.HSQL.Types: SqlUnknown :: Int -> SqlType
- Database.HSQL.Types: SqlUnknownField :: String -> SqlError
- Database.HSQL.Types: SqlUnsupportedOperation :: SqlError
- Database.HSQL.Types: SqlVarBinary :: Int -> SqlType
- Database.HSQL.Types: SqlVarChar :: Int -> SqlType
- Database.HSQL.Types: SqlWChar :: Int -> SqlType
- Database.HSQL.Types: SqlWLongVarChar :: Int -> SqlType
- Database.HSQL.Types: SqlWVarChar :: Int -> SqlType
- Database.HSQL.Types: SqlYear :: SqlType
- Database.HSQL.Types: Statement :: Connection -> IO () -> IO Bool -> (forall a. Int -> FieldDef -> (FieldDef -> CString -> Int -> IO a) -> IO a) -> [FieldDef] -> MVar Bool -> Statement
- Database.HSQL.Types: class SqlBind a
- Database.HSQL.Types: connBeginTransaction :: Connection -> IO ()
- Database.HSQL.Types: connClosed :: Connection -> MVar Bool
- Database.HSQL.Types: connCommitTransaction :: Connection -> IO ()
- Database.HSQL.Types: connDescribe :: Connection -> String -> IO [FieldDef]
- Database.HSQL.Types: connDisconnect :: Connection -> IO ()
- Database.HSQL.Types: connExecute :: Connection -> String -> IO ()
- Database.HSQL.Types: connQuery :: Connection -> String -> IO Statement
- Database.HSQL.Types: connRollbackTransaction :: Connection -> IO ()
- Database.HSQL.Types: connTables :: Connection -> IO [String]
- Database.HSQL.Types: data Connection
- Database.HSQL.Types: data SqlError
- Database.HSQL.Types: data SqlType
- Database.HSQL.Types: data Statement
- Database.HSQL.Types: fromSqlCStringLen :: (SqlBind a) => FieldDef -> CString -> Int -> IO a
- Database.HSQL.Types: fromSqlValue :: (SqlBind a) => SqlType -> String -> Maybe a
- Database.HSQL.Types: instance Eq SqlType
- Database.HSQL.Types: instance Show SqlError
- Database.HSQL.Types: instance Show SqlType
- Database.HSQL.Types: instance Typeable SqlError
- Database.HSQL.Types: seErrorMsg :: SqlError -> String
- Database.HSQL.Types: seFieldName :: SqlError -> String
- Database.HSQL.Types: seFieldType :: SqlError -> SqlType
- Database.HSQL.Types: seNativeError :: SqlError -> Int
- Database.HSQL.Types: seState :: SqlError -> String
- Database.HSQL.Types: sqlErrorTc :: TyCon
- Database.HSQL.Types: stmtClose :: Statement -> IO ()
- Database.HSQL.Types: stmtClosed :: Statement -> MVar Bool
- Database.HSQL.Types: stmtConn :: Statement -> Connection
- Database.HSQL.Types: stmtFetch :: Statement -> IO Bool
- Database.HSQL.Types: stmtFields :: Statement -> [FieldDef]
- Database.HSQL.Types: stmtGetCol :: Statement -> forall a. Int -> FieldDef -> (FieldDef -> CString -> Int -> IO a) -> IO a
- Database.HSQL.Types: toSqlValue :: (SqlBind a) => a -> String
- Database.HSQL.Types: type FieldDef = (String, SqlType, Bool)
+ DB.HSQL.Core: catchSql :: IO a -> (SqlError -> IO a) -> IO a
+ DB.HSQL.Core: checkHandle :: MVar Bool -> IO a -> IO a
+ DB.HSQL.Core: closeHandle :: MVar Bool -> IO () -> IO ()
+ DB.HSQL.Core: handleSql :: (SqlError -> IO a) -> IO a -> IO a
+ DB.HSQL.Core: sqlExceptions :: Exception x => x -> Maybe SqlError
+ DB.HSQL.Error: SqlBadTypeCast :: String -> SqlType -> SqlError
+ DB.HSQL.Error: SqlClosedHandle :: SqlError
+ DB.HSQL.Error: SqlError :: String -> Int -> String -> SqlError
+ DB.HSQL.Error: SqlFetchNull :: String -> SqlError
+ DB.HSQL.Error: SqlInvalidHandle :: SqlError
+ DB.HSQL.Error: SqlNeedData :: SqlError
+ DB.HSQL.Error: SqlNoData :: SqlError
+ DB.HSQL.Error: SqlStillExecuting :: SqlError
+ DB.HSQL.Error: SqlUnknownField :: String -> SqlError
+ DB.HSQL.Error: SqlUnsupportedOperation :: SqlError
+ DB.HSQL.Error: data SqlError
+ DB.HSQL.Error: instance Exception SqlError
+ DB.HSQL.Error: instance Show SqlError
+ DB.HSQL.Error: instance Typeable SqlError
+ DB.HSQL.Error: seErrorMsg :: SqlError -> String
+ DB.HSQL.Error: seFieldName :: SqlError -> String
+ DB.HSQL.Error: seFieldType :: SqlError -> SqlType
+ DB.HSQL.Error: seNativeError :: SqlError -> Int
+ DB.HSQL.Error: seState :: SqlError -> String
+ DB.HSQL.Error: sqlErrorTc :: TyCon
+ DB.HSQL.Type: SqlAbsTime :: SqlType
+ DB.HSQL.Type: SqlAbsTimeInterval :: SqlType
+ DB.HSQL.Type: SqlBLOB :: SqlType
+ DB.HSQL.Type: SqlBigInt :: SqlType
+ DB.HSQL.Type: SqlBinary :: Int -> SqlType
+ DB.HSQL.Type: SqlBit :: SqlType
+ DB.HSQL.Type: SqlBox :: SqlType
+ DB.HSQL.Type: SqlCIDRAddr :: SqlType
+ DB.HSQL.Type: SqlChar :: Int -> SqlType
+ DB.HSQL.Type: SqlCircle :: SqlType
+ DB.HSQL.Type: SqlDate :: SqlType
+ DB.HSQL.Type: SqlDateTime :: SqlType
+ DB.HSQL.Type: SqlDateTimeTZ :: SqlType
+ DB.HSQL.Type: SqlDecimal :: Int -> Int -> SqlType
+ DB.HSQL.Type: SqlDouble :: SqlType
+ DB.HSQL.Type: SqlENUM :: SqlType
+ DB.HSQL.Type: SqlFloat :: SqlType
+ DB.HSQL.Type: SqlINetAddr :: SqlType
+ DB.HSQL.Type: SqlInteger :: SqlType
+ DB.HSQL.Type: SqlLSeg :: SqlType
+ DB.HSQL.Type: SqlLine :: SqlType
+ DB.HSQL.Type: SqlLongVarBinary :: Int -> SqlType
+ DB.HSQL.Type: SqlLongVarChar :: Int -> SqlType
+ DB.HSQL.Type: SqlMacAddr :: SqlType
+ DB.HSQL.Type: SqlMedInt :: SqlType
+ DB.HSQL.Type: SqlMoney :: SqlType
+ DB.HSQL.Type: SqlNumeric :: Int -> Int -> SqlType
+ DB.HSQL.Type: SqlPath :: SqlType
+ DB.HSQL.Type: SqlPoint :: SqlType
+ DB.HSQL.Type: SqlPolygon :: SqlType
+ DB.HSQL.Type: SqlReal :: SqlType
+ DB.HSQL.Type: SqlRelTime :: SqlType
+ DB.HSQL.Type: SqlSET :: SqlType
+ DB.HSQL.Type: SqlSmallInt :: SqlType
+ DB.HSQL.Type: SqlText :: SqlType
+ DB.HSQL.Type: SqlTime :: SqlType
+ DB.HSQL.Type: SqlTimeInterval :: SqlType
+ DB.HSQL.Type: SqlTimeStamp :: SqlType
+ DB.HSQL.Type: SqlTimeTZ :: SqlType
+ DB.HSQL.Type: SqlTinyInt :: SqlType
+ DB.HSQL.Type: SqlUnknown :: Int -> SqlType
+ DB.HSQL.Type: SqlVarBinary :: Int -> SqlType
+ DB.HSQL.Type: SqlVarChar :: Int -> SqlType
+ DB.HSQL.Type: SqlWChar :: Int -> SqlType
+ DB.HSQL.Type: SqlWLongVarChar :: Int -> SqlType
+ DB.HSQL.Type: SqlWVarChar :: Int -> SqlType
+ DB.HSQL.Type: SqlYear :: SqlType
+ DB.HSQL.Type: data SqlType
+ DB.HSQL.Type: instance Eq SqlType
+ DB.HSQL.Type: instance Show SqlType
+ DB.HSQL.Type.Diverse: instance SqlBind Bool
+ DB.HSQL.Type.Diverse: instance SqlBind String
+ DB.HSQL.Type.Diverse: instance SqlBind a => SqlBind (Maybe a)
+ DB.HSQL.Type.Geometric: Box :: Double -> Double -> Double -> Double -> Box
+ DB.HSQL.Type.Geometric: Circle :: Point -> Double -> Circle
+ DB.HSQL.Type.Geometric: ClosedPath :: [Point] -> Path
+ DB.HSQL.Type.Geometric: Line :: Point -> Point -> Line
+ DB.HSQL.Type.Geometric: OpenPath :: [Point] -> Path
+ DB.HSQL.Type.Geometric: Point :: Double -> Double -> Point
+ DB.HSQL.Type.Geometric: Polygon :: [Point] -> Polygon
+ DB.HSQL.Type.Geometric: data Box
+ DB.HSQL.Type.Geometric: data Circle
+ DB.HSQL.Type.Geometric: data Line
+ DB.HSQL.Type.Geometric: data Path
+ DB.HSQL.Type.Geometric: data Point
+ DB.HSQL.Type.Geometric: data Polygon
+ DB.HSQL.Type.Geometric: instance Eq Box
+ DB.HSQL.Type.Geometric: instance Eq Circle
+ DB.HSQL.Type.Geometric: instance Eq Line
+ DB.HSQL.Type.Geometric: instance Eq Path
+ DB.HSQL.Type.Geometric: instance Eq Point
+ DB.HSQL.Type.Geometric: instance Eq Polygon
+ DB.HSQL.Type.Geometric: instance Show Box
+ DB.HSQL.Type.Geometric: instance Show Circle
+ DB.HSQL.Type.Geometric: instance Show Line
+ DB.HSQL.Type.Geometric: instance Show Path
+ DB.HSQL.Type.Geometric: instance Show Point
+ DB.HSQL.Type.Geometric: instance Show Polygon
+ DB.HSQL.Type.Geometric: instance SqlBind Box
+ DB.HSQL.Type.Geometric: instance SqlBind Circle
+ DB.HSQL.Type.Geometric: instance SqlBind Line
+ DB.HSQL.Type.Geometric: instance SqlBind Path
+ DB.HSQL.Type.Geometric: instance SqlBind Point
+ DB.HSQL.Type.Geometric: instance SqlBind Polygon
+ DB.HSQL.Type.NetAddress: INetAddr :: Int -> Int -> Int -> Int -> Int -> INetAddr
+ DB.HSQL.Type.NetAddress: MacAddr :: Int -> Int -> Int -> Int -> Int -> Int -> MacAddr
+ DB.HSQL.Type.NetAddress: data INetAddr
+ DB.HSQL.Type.NetAddress: data MacAddr
+ DB.HSQL.Type.NetAddress: instance Eq INetAddr
+ DB.HSQL.Type.NetAddress: instance Eq MacAddr
+ DB.HSQL.Type.NetAddress: instance Show INetAddr
+ DB.HSQL.Type.NetAddress: instance Show MacAddr
+ DB.HSQL.Type.NetAddress: instance SqlBind INetAddr
+ DB.HSQL.Type.NetAddress: instance SqlBind MacAddr
+ DB.HSQL.Type.Numeric: c_atoi :: CString -> IO Int
+ DB.HSQL.Type.Numeric: c_strtoll :: CString -> Ptr CString -> Int -> IO Int64
+ DB.HSQL.Type.Numeric: instance SqlBind Double
+ DB.HSQL.Type.Numeric: instance SqlBind Float
+ DB.HSQL.Type.Numeric: instance SqlBind Int
+ DB.HSQL.Type.Numeric: instance SqlBind Int64
+ DB.HSQL.Type.Numeric: instance SqlBind Integer
+ DB.HSQL.Type.Time: currTZ :: Int
+ DB.HSQL.Type.Time: f_read :: ReadP a -> String -> Maybe a
+ DB.HSQL.Type.Time: instance SqlBind ClockTime
+ DB.HSQL.Type.Time: mkClockTime :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> ClockTime
+ DB.HSQL.Type.Time: mktime :: Ptr () -> IO CTime
+ DB.HSQL.Type.Time: parseTZ :: ReadP Int
+ DB.HSQL.Type.Time: readDateTime :: ReadP (Int, Int, Int, Int, Int, Int)
+ DB.HSQL.Type.Time: readHMS :: ReadP (Int, Int, Int)
+ DB.HSQL.Type.Time: readYMD :: ReadP (Int, Int, Int)
+ Database.HSQL: INetAddr :: Int -> Int -> Int -> Int -> Int -> INetAddr
+ Database.HSQL: MacAddr :: Int -> Int -> Int -> Int -> Int -> Int -> MacAddr
+ Database.HSQL: data INetAddr
+ Database.HSQL: data MacAddr
- Database.HSQL: fromSqlCStringLen :: (SqlBind a) => FieldDef -> CString -> Int -> IO a
+ Database.HSQL: fromSqlCStringLen :: SqlBind a => FieldDef -> CString -> Int -> IO a
- Database.HSQL: getFieldValue :: (SqlBind a) => Statement -> String -> IO a
+ Database.HSQL: getFieldValue :: SqlBind a => Statement -> String -> IO a
- Database.HSQL: getFieldValue' :: (SqlBind a) => Statement -> String -> a -> IO a
+ Database.HSQL: getFieldValue' :: SqlBind a => Statement -> String -> a -> IO a
- Database.HSQL: getFieldValueMB :: (SqlBind a) => Statement -> String -> IO (Maybe a)
+ Database.HSQL: getFieldValueMB :: SqlBind a => Statement -> String -> IO (Maybe a)
- Database.HSQL: sqlExceptions :: Exception -> Maybe SqlError
+ Database.HSQL: sqlExceptions :: Exception x => x -> Maybe SqlError
Files
- ChangeLog +3/−0
- DB/HSQL/Core.hs +45/−0
- DB/HSQL/Error.hs +60/−0
- DB/HSQL/Type.hs +80/−0
- DB/HSQL/Type/Diverse.hs +43/−0
- DB/HSQL/Type/Geometric.hs +102/−0
- DB/HSQL/Type/NetAddress.hs +64/−0
- DB/HSQL/Type/Numeric.hs +119/−0
- DB/HSQL/Type/Time.hsc +143/−0
- Database/HSQL.hs +235/−0
- Database/HSQL.hsc +0/−607
- Database/HSQL/Types.hs +75/−137
- hsql.cabal +13/−4
+ ChangeLog view
@@ -0,0 +1,3 @@+2010-1-24+ 1.8.1: exception handling updated from Control.OldException to Control.Exception; + refactorings
+ DB/HSQL/Core.hs view
@@ -0,0 +1,45 @@+module DB.HSQL.Core where++import Prelude hiding(catch)+import Control.Monad(when,unless)+import Control.Exception(Exception,throw,catch,handle)+import Control.Concurrent.MVar(MVar,withMVar,modifyMVar_)+import Data.Dynamic(cast)++import DB.HSQL.Error(SqlError(SqlClosedHandle))++-- | if closed, nothing to do:+closeHandle :: MVar Bool -- ^ closing state ref+ -> IO () -- ^ DB action to do if not closed+ -> IO ()+closeHandle ref action =+ modifyMVar_ ref (\closed -> unless closed action + >> return True)++-- | if closed, exception:+checkHandle :: MVar Bool -- ^ closing state ref+ -> IO a -- ^ DB action to do if not closed+ -> IO a+checkHandle ref action =+ withMVar ref (\closed -> when closed (throw SqlClosedHandle) + >> action)+++------------------------------------------------------------------------------+-- routines for exception handling+------------------------------------------------------------------------------+-- | Casts, if possible, an Exception to an SqlError:+sqlExceptions :: Exception x + => x -- ^ the exception thinc to cast to SQLError+ -> Maybe SqlError+sqlExceptions = cast++-- | DEPRECATED: catchSql: Use Control.Exception.catch instead.+{-# DEPRECATED catchSql "Use Control.Exception.catch instead." #-}+catchSql :: IO a -> (SqlError -> IO a) -> IO a+catchSql = catch++-- | DEPRECATED: handleSql: Use Control.Exception.handle instead.+{-# DEPRECATED handleSql "Use Control.Exception.handle instead." #-}+handleSql :: (SqlError -> IO a) -> IO a -> IO a+handleSql = handle
+ DB/HSQL/Error.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE CPP,DeriveDataTypeable #-}+{-| Differentiation of DB specific error conditions.+-}+module DB.HSQL.Error(SqlError(..),sqlErrorTc) where++import Control.Exception(Exception(..),SomeException(..))+import Data.Dynamic(Typeable,TyCon,mkTyCon,cast)++import DB.HSQL.Type(SqlType)++-- | +data SqlError+ = SqlError { seState :: String+ , seNativeError :: Int+ , seErrorMsg :: String }+ | SqlNoData+ | SqlInvalidHandle+ | SqlStillExecuting+ | SqlNeedData+ | SqlBadTypeCast { seFieldName :: String+ , seFieldType :: SqlType }+ | SqlFetchNull { seFieldName :: String }+ | SqlUnknownField { seFieldName :: String }+ | SqlUnsupportedOperation+ | SqlClosedHandle+#ifdef __GLASGOW_HASKELL__+ deriving Typeable+#else++instance Typeable SqlError where+ typeOf _ = mkAppTy sqlErrorTc []+#endif++sqlErrorTc :: TyCon+sqlErrorTc = mkTyCon "Database.HSQL.SqlError"++-- |+instance Show SqlError where+ showsPrec _ (SqlError{seErrorMsg=msg}) = showString msg+ showsPrec _ SqlNoData = showString "No data"+ showsPrec _ SqlInvalidHandle = showString "Invalid handle"+ showsPrec _ SqlStillExecuting = showString "Stlll executing"+ showsPrec _ SqlNeedData = showString "Need data"+ showsPrec _ (SqlBadTypeCast name tp) = + showString ("The type of "++name++" field can't be converted to " + ++show tp++" type")+ showsPrec _ (SqlFetchNull name) = + showString ("The value of "++name++" field is null")+ showsPrec _ (SqlUnknownField name) = + showString ("Unknown field name: "++name)+ showsPrec _ SqlUnsupportedOperation = showString "Unsupported operation"+ showsPrec _ SqlClosedHandle = + showString "The referenced handle is already closed"++-- |+instance Exception SqlError where+ toException = SomeException+ fromException (SomeException exception) =+ cast exception+
+ DB/HSQL/Type.hs view
@@ -0,0 +1,80 @@+module DB.HSQL.Type where+{-| Differentiation of data types used in DBs.+-}++data SqlType+ -- numeric: + = SqlInteger -- ODBC, MySQL, PostgreSQL, MSI+ | SqlBigInt -- ODBC, MySQL, PostgreSQL, MSI+ | SqlSmallInt -- ODBC, MySQL, PostgreSQL+ | SqlTinyInt -- ODBC, MySQL, PostgreSQL+ | SqlMedInt -- , MySQL, + | SqlDecimal Int Int -- ODBC, MySQL, PostgreSQL+ | SqlNumeric Int Int -- ODBC, MySQL, PostgreSQL+ | SqlReal -- ODBC, MySQL, PostgreSQL+ | SqlDouble -- ODBC, MySQL, PostgreSQL+ | SqlFloat -- ODBC++ -- monetary:+ | SqlMoney -- , , PostgreSQL++ -- character:+ | SqlChar Int -- ODBC, MySQL, PostgreSQL+ | SqlVarChar Int -- ODBC, MySQL, PostgreSQL, MSI+ | SqlLongVarChar Int -- ODBC+ | SqlText -- , , PostgreSQL, MSI+ | SqlWChar Int -- ODBC+ | SqlWVarChar Int -- ODBC+ | SqlWLongVarChar Int -- ODBC++ -- date / time:+ | SqlDate -- ODBC, MySQL, PostgreSQL+ | SqlTime -- ODBC, MySQL, PostgreSQL+ | SqlTimeTZ -- , , PostgreSQL+ | SqlAbsTime -- , , PostgreSQL+ | SqlRelTime -- , , PostgreSQL+ | SqlTimeInterval -- , , PostgreSQL+ | SqlAbsTimeInterval -- , , PostgreSQL+ | SqlTimeStamp -- ODBC, MySQL+ | SqlDateTime -- , MySQL+ | SqlDateTimeTZ -- , MySQL, PostgreSQL+ | SqlYear -- , MySQL++ -- booleans:+ | SqlBit -- ODBC, , PostgreSQL++ -- enums:+ | SqlENUM -- , MySQL++ -- geometric types:+ | SqlPoint -- , , PostgreSQL+ | SqlLSeg -- , , PostgreSQL+ | SqlPath -- , , PostgreSQL+ | SqlBox -- , , PostgreSQL+ | SqlPolygon -- , , PostgreSQL+ | SqlLine -- , , PostgreSQL + | SqlCircle -- , , PostgreSQL++ -- network addresses:+ | SqlINetAddr -- , , PostgreSQL+ | SqlCIDRAddr -- , , PostgreSQL+ | SqlMacAddr -- , , PostgreSQL++ -- bit strings:+ | SqlBinary Int -- ODBC, , PostgreSQL+ | SqlVarBinary Int -- ODBC, , PostgreSQL+ | SqlLongVarBinary Int -- ODBC++ -- collections:+ | SqlSET -- , MySQL+ + -- lobs:+ | SqlBLOB -- , MySQL, , MSI++ -- unknown:+ | SqlUnknown Int -- ^ HSQL returns @SqlUnknown tp@ for all+ -- columns for which it cannot determine+ -- the right type. The @tp@ here is the+ -- internal type code returned from the+ -- backend library+ deriving (Eq, Show)
+ DB/HSQL/Type/Diverse.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE TypeSynonymInstances #-}+module DB.HSQL.Type.Diverse where++import Foreign(nullPtr)++import DB.HSQL.Type(SqlType(SqlBit))+import Database.HSQL.Types(SqlBind(..))++-- |+instance SqlBind String where+ fromSqlValue _ = Just++ toSqlValue s = '\'' : foldr mapChar "'" s+ where+ mapChar '\\' s = '\\':'\\':s+ mapChar '\'' s = '\\':'\'':s+ mapChar '\n' s = '\\':'n' :s+ mapChar '\r' s = '\\':'r' :s+ mapChar '\t' s = '\\':'t' :s+ mapChar '\NUL' s = '\\':'0' :s+ mapChar c s = c :s+++-- |+instance SqlBind Bool where+ fromSqlValue SqlBit s = Just (s == "t")+ fromSqlValue _ _ = Nothing++ toSqlValue True = "'t'"+ toSqlValue False = "'f'"+++-- |+instance SqlBind a => SqlBind (Maybe a) where+ fromSqlCStringLen fieldDef cstr cstrLen+ | cstr == nullPtr = return Nothing+ | otherwise = do v <- fromSqlCStringLen fieldDef cstr cstrLen+ return (Just v)+ + fromSqlValue tp s = Just (fromSqlValue tp s)++ toSqlValue (Just v) = toSqlValue v+ toSqlValue Nothing = "null"
+ DB/HSQL/Type/Geometric.hs view
@@ -0,0 +1,102 @@+module DB.HSQL.Type.Geometric where++import DB.HSQL.Type+ (SqlType(SqlPoint,SqlLSeg,SqlPath,SqlBox,SqlPolygon,SqlCircle))+import Database.HSQL.Types(SqlBind(..))++-- |+data Point + = Point Double Double + deriving (Eq, Show)++instance SqlBind Point where+ fromSqlValue SqlPoint s = case read s of+ (x,y) -> Just (Point x y)+ fromSqlValue _ _ = Nothing++ toSqlValue (Point x y) = + '\'' : shows (x,y) "'"+++-- |+data Line + = Line Point Point + deriving (Eq, Show)++instance SqlBind Line where+ fromSqlValue SqlLSeg s = + case read s of+ [(x1,y1),(x2,y2)] -> Just (Line (Point x1 y1) (Point x2 y2))+ fromSqlValue _ _ = Nothing++ toSqlValue (Line (Point x1 y1) (Point x2 y2)) = + '\'' : shows [(x1,y1),(x2,y2)] "'"+++-- |+data Path + = OpenPath [Point] + | ClosedPath [Point] + deriving (Eq, Show)++instance SqlBind Path where+ fromSqlValue SqlPath ('(':s) = + case read ("["++init s++"]") of -- closed path+ ps -> Just (ClosedPath (map (\(x,y) -> Point x y) ps))+ fromSqlValue SqlPath s = + case read s of -- closed path -- open path+ ps -> Just (OpenPath (map (\(x,y) -> Point x y) ps))+ fromSqlValue SqlLSeg s = + case read s of+ [(x1,y1),(x2,y2)] -> Just (OpenPath [(Point x1 y1), (Point x2 y2)])+ fromSqlValue SqlPoint s = + case read s of+ (x,y) -> Just (ClosedPath [Point x y])+ fromSqlValue _ _ = Nothing++ toSqlValue (OpenPath ps) = '\'' : shows ps "'"+ toSqlValue (ClosedPath ps) = "'(" ++ init (tail (show ps)) ++ "')"+++-- |+data Box + = Box Double Double Double Double + deriving (Eq, Show)++instance SqlBind Box where+ fromSqlValue SqlBox s = case read ("("++s++")") of+ ((x1,y1),(x2,y2)) -> Just (Box x1 y1 x2 y2)+ fromSqlValue _ _ = Nothing++ toSqlValue (Box x1 y1 x2 y2) = + '\'' : shows ((x1,y1),(x2,y2)) "'"+++-- |+data Polygon + = Polygon [Point] + deriving (Eq, Show)++instance SqlBind Polygon where+ fromSqlValue SqlPolygon s = + case read ("["++init (tail s)++"]") of+ ps -> Just (Polygon (map (\(x,y) -> Point x y) ps))+ fromSqlValue _ _ = Nothing++ toSqlValue (Polygon ps) = + "'(" ++ init (tail (show ps)) ++ "')"+++-- | +data Circle + = Circle Point Double + deriving (Eq, Show)++instance SqlBind Circle where+ fromSqlValue SqlCircle s = case read ("("++init (tail s)++")") of+ ((x,y),r) -> Just (Circle (Point x y) r)+ fromSqlValue _ _ = Nothing++ toSqlValue (Circle (Point x y) r) = + "'<" ++ show (x,y) ++ "," ++ show r ++ "'>"+
+ DB/HSQL/Type/NetAddress.hs view
@@ -0,0 +1,64 @@+module DB.HSQL.Type.NetAddress where++import Data.Char(intToDigit)+import Numeric(readHex,showIntAtBase,readDec)++import DB.HSQL.Type(SqlType(SqlINetAddr,SqlCIDRAddr,SqlMacAddr))+import Database.HSQL.Types(SqlBind(..))++-- | +data INetAddr + = INetAddr Int Int Int Int Int + deriving (Eq,Show)++instance SqlBind INetAddr where+ fromSqlValue t s+ | t == SqlINetAddr || t == SqlCIDRAddr =+ case readNum s of+ (x1,s) -> case readNum s of+ (x2,s) -> case readNum s of+ (x3,s) -> case readNum s of+ (x4,s) -> case readNum s of+ (mask,_) -> Just (INetAddr x1 x2 x3 x4 mask)+ | otherwise = Nothing+ where readNum s = case readDec s of+ [(x,'.':s)] -> (x,s)+ [(x,'/':s)] -> (x,s)+ [(x,"")] -> (x,"")+ _ -> (0,"")++ toSqlValue (INetAddr x1 x2 x3 x4 mask) = + '\'' : (shows x1 . dot .+ shows x2. dot .+ shows x3 . dot .+ shows x4 . slash .+ shows mask) "'"+ where dot = showChar '.'+ slash = showChar '/'+++-- | +data MacAddr + = MacAddr Int Int Int Int Int Int + deriving (Eq,Show)++instance SqlBind MacAddr where+ fromSqlValue SqlMacAddr s =+ case readHex s of+ [(x1,':':s)] -> case readHex s of+ [(x2,':':s)] -> case readHex s of+ [(x3,':':s)] -> case readHex s of+ [(x4,':':s)] -> case readHex s of+ [(x5,':':s)] -> case readHex s of+ [(x6,_)] -> Just (MacAddr x1 x2 x3 x4 x5 x6)+ fromSqlValue _ _ = Nothing++ toSqlValue (MacAddr x1 x2 x3 x4 x5 x6) = + '\'' : (showHex x1 . colon .+ showHex x2 . colon .+ showHex x3 . colon .+ showHex x4 . colon .+ showHex x5 .colon .+ showHex x6) "'"+ where colon = showChar ':'+ showHex = showIntAtBase 16 intToDigit
+ DB/HSQL/Type/Numeric.hs view
@@ -0,0 +1,119 @@+{-# LANGUAGE CPP,ForeignFunctionInterface #-}+module DB.HSQL.Type.Numeric where++import Control.Exception(throw)+import Data.Int(Int64)+import Foreign(Ptr,nullPtr)+import Foreign.C(CString)++import DB.HSQL.Type+ (SqlType(SqlReal,SqlFloat,SqlDouble,SqlNumeric,SqlDecimal+ ,SqlBigInt,SqlTinyInt,SqlInteger,SqlMedInt,SqlSmallInt+ ,SqlText))+import DB.HSQL.Error(SqlError(SqlFetchNull,SqlBadTypeCast))+import Database.HSQL.Types(SqlBind(..))++-- |+foreign import ccall "stdlib.h atoi" + c_atoi :: CString -> IO Int++#ifdef mingw32_TARGET_OS+foreign import ccall "stdlib.h _atoi64" + c_atoi64 :: CString -> IO Int64+#else+foreign import ccall "stdlib.h strtoll" + c_strtoll :: CString -> Ptr CString -> Int -> IO Int64+#endif+++-- |+instance SqlBind Int where+ fromSqlCStringLen (name,sqlType,_) cstr cstrLen+ | cstr == nullPtr = throw (SqlFetchNull name)+ | sqlType==SqlInteger || + sqlType==SqlMedInt ||+ sqlType==SqlTinyInt ||+ sqlType==SqlSmallInt||+ sqlType==SqlBigInt = c_atoi cstr+ | otherwise = throw (SqlBadTypeCast name sqlType)++ fromSqlValue SqlInteger s = Just (read s)+ fromSqlValue SqlMedInt s = Just (read s)+ fromSqlValue SqlTinyInt s = Just (read s)+ fromSqlValue SqlSmallInt s = Just (read s)+ fromSqlValue SqlBigInt s = Just (read s)+ fromSqlValue SqlDouble s = Just (truncate (read s :: Double))+ fromSqlValue SqlText s = Just (read s)+ fromSqlValue _ _ = Nothing++ toSqlValue s = show s+++-- |+instance SqlBind Int64 where+ fromSqlCStringLen (name,sqlType,_) cstr cstrLen+ | cstr == nullPtr = throw (SqlFetchNull name)+ | sqlType==SqlInteger ||+ sqlType==SqlMedInt ||+ sqlType==SqlTinyInt ||+ sqlType==SqlSmallInt||+ sqlType==SqlBigInt =++#ifdef mingw32_TARGET_OS+ c_atoi64 cstr+#else+ c_strtoll cstr nullPtr 10+#endif++ | otherwise = throw (SqlBadTypeCast name sqlType)++ fromSqlValue SqlInteger s = Just (read s)+ fromSqlValue SqlMedInt s = Just (read s)+ fromSqlValue SqlTinyInt s = Just (read s)+ fromSqlValue SqlSmallInt s = Just (read s)+ fromSqlValue SqlBigInt s = Just (read s)+ fromSqlValue SqlDouble s = Just (truncate (read s :: Double))+ fromSqlValue SqlText s = Just (read s)+ fromSqlValue _ s = Nothing++ toSqlValue val = show val+++-- |+instance SqlBind Integer where+ fromSqlValue SqlInteger s = Just (read s)+ fromSqlValue SqlMedInt s = Just (read s)+ fromSqlValue SqlTinyInt s = Just (read s)+ fromSqlValue SqlSmallInt s = Just (read s)+ fromSqlValue SqlBigInt s = Just (read s)+ fromSqlValue SqlDouble s = Just (truncate (read s :: Double))+ fromSqlValue SqlText s = Just (read s)+ fromSqlValue _ _ = Nothing++ toSqlValue s = show s+++-- |+instance SqlBind Double where+ fromSqlValue (SqlDecimal _ _) s = Just (read s)+ fromSqlValue (SqlNumeric _ _) s = Just (read s)+ fromSqlValue SqlDouble s = Just (read s)+ fromSqlValue SqlReal s = Just (read s)+ fromSqlValue SqlFloat s = Just (read s)+ fromSqlValue SqlText s = Just (read s)+ fromSqlValue _ _ = Nothing++ toSqlValue d = show d+++-- |+instance SqlBind Float where+ fromSqlValue (SqlDecimal _ _) s = Just (read s)+ fromSqlValue (SqlNumeric _ _) s = Just (read s)+ fromSqlValue SqlDouble s = Just (read s)+ fromSqlValue SqlReal s = Just (read s)+ fromSqlValue SqlFloat s = Just (read s)+ fromSqlValue SqlText s = Just (read s)+ fromSqlValue _ _ = Nothing++ toSqlValue d = show d
+ DB/HSQL/Type/Time.hsc view
@@ -0,0 +1,143 @@+{-# LANGUAGE CPP,ForeignFunctionInterface #-}+module DB.HSQL.Type.Time where++import Control.Monad(mplus)+import System.IO.Unsafe(unsafePerformIO)+import System.Time(ClockTime(..),CalendarTime(..)+ ,getClockTime,toCalendarTime,toUTCTime)+import Text.ParserCombinators.ReadP(ReadP,char,skipSpaces,readP_to_S)+import Text.Read.Lex(readDecP)+import Foreign(Ptr,allocaBytes,pokeByteOff)+import Foreign.C(CTime,CInt)++import DB.HSQL.Type+ (SqlType(SqlTimeTZ,SqlTime,SqlDate,SqlDateTimeTZ,SqlDateTime+ ,SqlTimeStamp,SqlText))+import Database.HSQL.Types(SqlBind(..))++#include <time.h>++-- |+mkClockTime :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> ClockTime+mkClockTime year mon mday hour min sec tz =+ unsafePerformIO $ do+ allocaBytes (#const sizeof(struct tm)) $ \p_tm -> do+ (#poke struct tm,tm_sec ) p_tm (fromIntegral sec :: CInt)+ (#poke struct tm,tm_min ) p_tm (fromIntegral min :: CInt)+ (#poke struct tm,tm_hour ) p_tm (fromIntegral hour :: CInt)+ (#poke struct tm,tm_mday ) p_tm (fromIntegral mday :: CInt)+ (#poke struct tm,tm_mon ) p_tm (fromIntegral (mon-1) :: CInt)+ (#poke struct tm,tm_year ) p_tm (fromIntegral (year-1900) :: CInt)+ (#poke struct tm,tm_isdst) p_tm (-1 :: CInt)+ t <- mktime p_tm+ let t'=+#if __GLASGOW_HASKELL__ >= 603+ fromEnum t+#else+ t+#endif+ return (TOD (fromIntegral t' + fromIntegral (tz-currTZ)) 0)++foreign import ccall unsafe + mktime :: Ptr () -> IO CTime++-- |+{-# NOINLINE currTZ #-}+currTZ :: Int+currTZ = + ctTZ (unsafePerformIO (getClockTime >>= toCalendarTime)) -- Hack++-- |+parseTZ :: ReadP Int+parseTZ = + (char '+' >> readDecP) `mplus` (char '-' >> fmap negate readDecP)++-- |+f_read :: ReadP a -> String -> Maybe a+f_read f s = case readP_to_S f s of + [(x,_)] -> Just x++-- |+readHMS :: ReadP (Int, Int, Int)+readHMS = do+ hour <- readDecP+ char ':'+ minutes <- readDecP+ char ':'+ seconds <- readDecP+ return (hour, minutes, seconds)++-- |+readYMD :: ReadP (Int, Int, Int)+readYMD = do+ year <- readDecP+ char '-'+ month <- readDecP+ char '-'+ day <- readDecP+ return (year, month, day)++-- |+readDateTime :: ReadP (Int, Int, Int, Int, Int, Int)+readDateTime = do+ (year, month, day) <- readYMD+ skipSpaces+ (hour, minutes, seconds) <- readHMS+ return (year, month, day, hour, minutes, seconds)+++-- |+instance SqlBind ClockTime where+ fromSqlValue SqlTimeTZ s = f_read getTimeTZ s+ where getTimeTZ :: ReadP ClockTime+ getTimeTZ = do+ (hour, minutes, seconds) <- readHMS+ (char '.' >> readDecP) `mplus` (return 0)+ tz <- parseTZ+ return (mkClockTime 1970 1 1 hour minutes seconds (tz*3600))+ fromSqlValue SqlTime s = f_read getTime s+ where getTime :: ReadP ClockTime+ getTime = do+ (hour, minutes, seconds) <- readHMS+ return (mkClockTime 1970 1 1 hour minutes seconds currTZ)+ fromSqlValue SqlDate s = f_read getDate s+ where getDate :: ReadP ClockTime+ getDate = do+ (year, month, day) <- readYMD+ return (mkClockTime year month day 0 0 0 currTZ)+ fromSqlValue SqlDateTimeTZ s = f_read getDateTimeTZ s+ where getDateTimeTZ :: ReadP ClockTime+ getDateTimeTZ = do+ (year, month, day, hour, minutes, seconds) <- readDateTime+ char '.' >> readDecP -- ) `mplus` (return 0)+ tz <- parseTZ+ return (mkClockTime year month day + hour minutes seconds + (tz*3600))+ -- The only driver which seems to report the type as SqlTimeStamp seems+ -- to be the MySQL driver. MySQL (at least 4.1) uses the same format for+ -- datetime and timestamp columns.+ -- Allow SqlText to support SQLite, which reports everything as SqlText+ fromSqlValue t s + | t == SqlDateTime || t == SqlTimeStamp || t == SqlText = + f_read getDateTime s+ where getDateTime :: ReadP ClockTime+ getDateTime = do+ (year, month, day, hour, minutes, seconds) <- + readDateTime+ return (mkClockTime year month day + hour minutes seconds + currTZ)+ fromSqlValue _ _ = Nothing++ toSqlValue ct = + '\'' : (shows (ctYear t) . score .+ shows (ctMonth t) . score .+ shows (ctDay t) . space .+ shows (ctHour t) . colon .+ shows (ctMin t) . colon .+ shows (ctSec t)) "'"+ where t = toUTCTime ct+ score = showChar '-'+ space = showChar ' '+ colon = showChar ':'
+ Database/HSQL.hs view
@@ -0,0 +1,235 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-| Module : Database.HSQL+ Copyright : (c) Krasimir Angelov 2003+ License : BSD-style++ Maintainer : ka2_mail@yahoo.com+ Stability : provisional+ Portability : portable++ The module provides an abstract database interface+-}+module Database.HSQL+ (+ -- * Connect\/Disconnect+ Connection+ , disconnect -- :: Connection -> IO ()+ + -- * Command Execution Functions+ -- | Once a connection to a database has been successfully established, + -- the functions described here are used to perform+ -- SQL queries and commands.+ , execute -- :: Connection -> String -> IO ()+ , Statement+ , query -- :: Connection -> String -> IO Statement+ , closeStatement -- :: Statement -> IO ()+ , fetch -- :: Statement -> IO Bool+ + -- * Retrieving Statement values and types+ , FieldDef, SqlBind(..)+ , getFieldValue -- :: SqlBind a => Statement -> String -> IO a+ , getFieldValueMB + , getFieldValue' -- :: SqlBind a => Statement -> String -> a -> IO a+ , getFieldValueType -- :: Statement -> String -> (SqlType, Bool)+ , getFieldsTypes -- :: Statement -> [(String, SqlType, Bool)]+ + -- * Transactions+ , inTransaction -- :: Connection -> (Connection -> IO a) -> IO a+ + -- * Utilities+ , forEachRow -- :: (Statement -> s -> IO s) -- ^ an action+ , forEachRow' -- :: (Statement -> IO ()) -> Statement -> IO ()+ , collectRows -- :: (Statement -> IO a) -> Statement -> IO [a]++ -- * SQL Exceptions handling+ , SqlError(..)+ , catchSql+ , handleSql+ , sqlExceptions -- :: Exception -> Maybe SqlError+ + -- * Metadata+ , tables -- :: Connection -> IO [String]+ , describe -- :: Connection -> String -> IO [FieldDef]++ -- * Extra types+ , Point(..), Line(..), Path(..), Box(..), Circle(..), Polygon(..)+ , INetAddr(..), MacAddr(..)+ , SqlType(..)+ ) where++import Prelude hiding(catch)+import Control.Monad(when)+import Control.Exception(SomeException,finally,throwIO,throw,catch)++import DB.HSQL.Type+import DB.HSQL.Type.Numeric+import DB.HSQL.Type.Time+import DB.HSQL.Type.Geometric+import DB.HSQL.Type.NetAddress+import DB.HSQL.Type.Diverse()+import DB.HSQL.Error+import DB.HSQL.Core+import Database.HSQL.Types(FieldDef,Connection(..),Statement(..)+ ,SqlBind(fromSqlCStringLen))++------------------------------------------------------------------------------+-- Operations on the connection+------------------------------------------------------------------------------+-- | Closes the connection. Performing 'disconnect' on a connection that has+-- already been closed has no effect.+-- All other operations on a closed connection will fail.+disconnect :: Connection -> IO ()+disconnect conn = + closeHandle (connClosed conn) (connDisconnect conn)+ +-- | Submits a command to the database.+execute :: Connection -- ^ the database connection+ -> String -- ^ the text of SQL command+ -> IO ()+execute conn query = + checkHandle (connClosed conn) (connExecute conn query)++-- | Executes a query and returns a result set+query :: Connection -- ^ the database connection+ -> String -- ^ the text of SQL query+ -> IO Statement -- ^ the associated statement. Must be closed with + -- the 'closeStatement' function+query conn query = + checkHandle (connClosed conn) (connQuery conn query)++-- | List all tables in the database.+tables :: Connection -- ^ Database connection+ -> IO [String] -- ^ The names of all tables in the database.+tables conn = + checkHandle (connClosed conn) (connTables conn)++-- | List all columns in a table along with their types and @nullable@ flags+describe :: Connection -- ^ Database connection+ -> String -- ^ Name of a database table+ -> IO [FieldDef] -- ^ The list of fields in the table+describe conn table = + checkHandle (connClosed conn) (connDescribe conn table)++------------------------------------------------------------------------------+-- transactions+------------------------------------------------------------------------------++-- | The 'inTransaction' function executes the specified action in transaction+-- mode.+-- If the action completes successfully then the transaction will be commited.+-- If the action completes with an exception then the transaction will be+-- rolled back and the exception will be throw again.+-- A transaction is to catch ANY exception, so 'SomeException' is adequate.+inTransaction :: Connection -- ^ Database connection+ -> (Connection -> IO a) -- ^ an action+ -> IO a -- ^ the returned value is the result+ -- returned from action+inTransaction conn action = do+ checkHandle (connClosed conn) (connBeginTransaction conn)+ r <- catch (action conn) + (\(err::SomeException) -> do + checkHandle (connClosed conn) + (connRollbackTransaction conn)+ throwIO err)+ checkHandle (connClosed conn) (connCommitTransaction conn)+ return r++------------------------------------------------------------------------------+-- Operations on the statements+------------------------------------------------------------------------------+-- | 'fetch' fetches the next rowset of data from the result set.+-- The values from columns can be retrieved with 'getFieldValue' function.+fetch :: Statement -> IO Bool+fetch stmt = checkHandle (stmtClosed stmt) (stmtFetch stmt)++-- | 'closeStatement' stops processing associated with a specific statement,+-- closes any open cursors associated with the statement, discards pending+-- results, and frees all resources associated with the statement.+-- Performing 'closeStatement' on a statement that has already been closed+-- has no effect. All other operations on a closed statement will fail.+closeStatement :: Statement -> IO ()+closeStatement stmt = closeHandle (stmtClosed stmt) (stmtClose stmt)++-- | Returns the type and the @nullable@ flag for field with specified name+getFieldValueType :: Statement -> String -> (SqlType, Bool)+getFieldValueType stmt name = (sqlType, nullable)+ where (sqlType,nullable,colNumber) = + findFieldInfo name (stmtFields stmt) 0++-- | Returns the list of fields with their types and @nullable@ flags+getFieldsTypes :: Statement -> [(String, SqlType, Bool)]+getFieldsTypes stmt = stmtFields stmt++findFieldInfo :: String -> [FieldDef] -> Int -> (SqlType,Bool,Int)+findFieldInfo name [] colNumber = throw (SqlUnknownField name)+findFieldInfo name (fieldDef@(name',sqlType,nullable):fields) colNumber+ | name == name' = (sqlType,nullable,colNumber)+ | otherwise = findFieldInfo name fields $! (colNumber+1)+++------------------------------------------------------------------------------+-- binding+------------------------------------------------------------------------------+-- | Retrieves the value of field with the specified name.+getFieldValue :: SqlBind a => Statement -- ^ result table data+ -> String -- ^ field name+ -> IO a -- ^ field value+getFieldValue stmt name = do+ stmtGetCol stmt colNumber (name,sqlType,nullable) fromSqlCStringLen+ where (sqlType,nullable,colNumber) = + findFieldInfo name (stmtFields stmt) 0++{-# DEPRECATED getFieldValueMB "Use getFieldValue instead." #-}+getFieldValueMB :: SqlBind a => Statement -> String -> IO (Maybe a)+getFieldValueMB = getFieldValue++-- | Retrieves the value of field with the specified name.+-- If the field value is @null@ then the function will return the default value.+getFieldValue' :: SqlBind a => Statement+ -> String -- ^ Field name+ -> a -- ^ Default field value+ -> IO a -- ^ Field value+getFieldValue' stmt name def = do+ mb_v <- getFieldValue stmt name+ return (case mb_v of { Nothing -> def; Just a -> a })+++------------------------------------------------------------------------------+-- helpers+------------------------------------------------------------------------------+-- | The 'forEachRow' function iterates through the result set in 'Statement'+-- and executes the given action for each row in the set.+-- The function closes the 'Statement' after the last row processing or if+-- the given action raises an exception.+forEachRow :: (Statement -> s -> IO s) -- ^ an action+ -> Statement -- ^ the statement+ -> s -- ^ initial state+ -> IO s -- ^ final state+forEachRow f stmt s = loop s `finally` closeStatement stmt+ where loop s = do success <- fetch stmt+ if success then f stmt s >>= loop else return s++-- | The 'forEachRow\'' function is analogous to 'forEachRow' but doesn't+-- provide state.+-- The function closes the 'Statement' after the last row processing or if the+-- given action raises an exception.+forEachRow' :: (Statement -> IO ()) -> Statement -> IO ()+forEachRow' f stmt = loop `finally` closeStatement stmt+ where loop = do success <- fetch stmt+ when success (f stmt >> loop)++-- | The 'collectRows' function iterates through the result set in 'Statement'+-- and executes the given action for each row in the set. The values returned+-- from action are collected and returned as list. The function closes the+-- 'Statement' after the last row processing or if the given action raises an+-- exception.+collectRows :: (Statement -> IO a) -> Statement -> IO [a]+collectRows f stmt = loop `finally` closeStatement stmt+ where loop = do success <- fetch stmt+ if success+ then do x <- f stmt+ xs <- loop+ return (x:xs)+ else return []++
− Database/HSQL.hsc
@@ -1,607 +0,0 @@-------------------------------------------------------------------------------------------{-| Module : Database.HSQL.ODBC- Copyright : (c) Krasimir Angelov 2003- License : BSD-style-- Maintainer : ka2_mail@yahoo.com- Stability : provisional- Portability : portable-- The module provides an abstract database interface--}--------------------------------------------------------------------------------------------module Database.HSQL- (- -- * Connect\/Disconnect- Connection- , disconnect -- :: Connection -> IO ()- - -- * Command Execution Functions- -- | Once a connection to a database has been successfully established, - -- the functions described here are used to perform SQL queries and commands.- , execute -- :: Connection -> String -> IO ()- , Statement- , query -- :: Connection -> String -> IO Statement- , closeStatement -- :: Statement -> IO ()- , fetch -- :: Statement -> IO Bool- - -- * Retrieving Statement values and types- , FieldDef, SqlType(..), SqlBind(..)- , getFieldValue -- :: SqlBind a => Statement -> String -> IO a- , getFieldValueMB- , getFieldValue' -- :: SqlBind a => Statement -> String -> a -> IO a- , getFieldValueType -- :: Statement -> String -> (SqlType, Bool)- , getFieldsTypes -- :: Statement -> [(String, SqlType, Bool)]- - -- * Transactions- , inTransaction -- :: Connection -> (Connection -> IO a) -> IO a-- - -- * SQL Exceptions handling- , SqlError(..)- , catchSql -- :: IO a -> (SqlError -> IO a) -> IO a- , handleSql -- :: (SqlError -> IO a) -> IO a -> IO a- , sqlExceptions -- :: Exception -> Maybe SqlError- - -- * Utilities- , forEachRow -- :: (Statement -> s -> IO s) -- ^ an action- , forEachRow' -- :: (Statement -> IO ()) -> Statement -> IO ()- , collectRows -- :: (Statement -> IO a) -> Statement -> IO [a]- - -- * Metadata- , tables -- :: Connection -> IO [String]- , describe -- :: Connection -> String -> IO [FieldDef]-- -- * Extra types- , Point(..), Line(..), Path(..), Box(..), Circle(..), Polygon(..)- ) where--import Prelude hiding (catch)-import Foreign-import Foreign.C-import Data.Int-import Data.Char-import Data.Dynamic-import System.Time-import System.IO.Unsafe(unsafePerformIO)-import Control.Monad(when,unless,mplus)-import Control.Exception (throwDyn, catchDyn, dynExceptions, Exception(..), finally, catch, throwIO)-import Control.Concurrent.MVar-import Text.ParserCombinators.ReadP-import Text.Read-import Text.Read.Lex-import Numeric-import Database.HSQL.Types--#include <time.h>---------------------------------------------------------------------------------------------- routines for exception handling--------------------------------------------------------------------------------------------catchSql :: IO a -> (SqlError -> IO a) -> IO a-catchSql = catchDyn--handleSql :: (SqlError -> IO a) -> IO a -> IO a-handleSql h f = catchDyn f h--sqlExceptions :: Exception -> Maybe SqlError-sqlExceptions e = dynExceptions e >>= fromDynamic--checkHandle :: MVar Bool -> IO a -> IO a-checkHandle ref action =- withMVar ref (\closed -> when closed (throwDyn SqlClosedHandle) >> action)--closeHandle :: MVar Bool -> IO () -> IO ()-closeHandle ref action =- modifyMVar_ ref (\closed -> unless closed action >> return True)---------------------------------------------------------------------------------------------- Operations on the connection---------------------------------------------------------------------------------------------- | Closes the connection. Performing 'disconnect' on a connection that has already been --- closed has no effect. All other operations on a closed connection will fail.-disconnect :: Connection -> IO ()-disconnect conn = closeHandle (connClosed conn) (connDisconnect conn)- --- | Submits a command to the database.-execute :: Connection -- ^ the database connection- -> String -- ^ the text of SQL command- -> IO ()-execute conn query = checkHandle (connClosed conn) (connExecute conn query)---- | Executes a query and returns a result set-query :: Connection -- ^ the database connection- -> String -- ^ the text of SQL query- -> IO Statement -- ^ the associated statement. Must be closed with - -- the 'closeStatement' function-query conn query = checkHandle (connClosed conn) (connQuery conn query)- ---- | List all tables in the database.-tables :: Connection -- ^ Database connection- -> IO [String] -- ^ The names of all tables in the database.-tables conn = checkHandle (connClosed conn) (connTables conn)---- | List all columns in a table along with their types and @nullable@ flags-describe :: Connection -- ^ Database connection- -> String -- ^ Name of a database table- -> IO [FieldDef] -- ^ The list of fields in the table-describe conn table = checkHandle (connClosed conn) (connDescribe conn table)---------------------------------------------------------------------------------------------- transactions---------------------------------------------------------------------------------------------- | The 'inTransaction' function executes the specified action in transaction mode.--- If the action completes successfully then the transaction will be commited.--- If the action completes with an exception then the transaction will be rolled back--- and the exception will be throw again.-inTransaction :: Connection- -> (Connection -> IO a) -- ^ an action- -> IO a -- ^ the returned value is the result returned from action-inTransaction conn action = do- checkHandle (connClosed conn) (connBeginTransaction conn)- r <- catch (action conn) (\err -> do- checkHandle (connClosed conn) (connRollbackTransaction conn)- throwIO err)- checkHandle (connClosed conn) (connCommitTransaction conn)- return r---------------------------------------------------------------------------------------------- Operations on the statements---------------------------------------------------------------------------------------------- | 'fetch' fetches the next rowset of data from the result set.--- The values from columns can be retrieved with 'getFieldValue' function.-fetch :: Statement -> IO Bool-fetch stmt = checkHandle (stmtClosed stmt) (stmtFetch stmt)---- | 'closeStatement' stops processing associated with a specific statement, closes any open cursors--- associated with the statement, discards pending results, and frees all resources associated with--- the statement. Performing 'closeStatement' on a statement that has already been --- closed has no effect. All other operations on a closed statement will fail.-closeStatement :: Statement -> IO ()-closeStatement stmt = closeHandle (stmtClosed stmt) (stmtClose stmt)---- | Returns the type and the @nullable@ flag for field with specified name-getFieldValueType :: Statement -> String -> (SqlType, Bool)-getFieldValueType stmt name = (sqlType, nullable)- where- (sqlType,nullable,colNumber) = findFieldInfo name (stmtFields stmt) 0---- | Returns the list of fields with their types and @nullable@ flags-getFieldsTypes :: Statement -> [(String, SqlType, Bool)]-getFieldsTypes stmt = stmtFields stmt--findFieldInfo :: String -> [FieldDef] -> Int -> (SqlType,Bool,Int)-findFieldInfo name [] colNumber = throwDyn (SqlUnknownField name)-findFieldInfo name (fieldDef@(name',sqlType,nullable):fields) colNumber- | name == name' = (sqlType,nullable,colNumber)- | otherwise = findFieldInfo name fields $! (colNumber+1)---------------------------------------------------------------------------------------------- binding--------------------------------------------------------------------------------------------foreign import ccall "stdlib.h atoi" c_atoi :: CString -> IO Int-#ifdef mingw32_TARGET_OS-foreign import ccall "stdlib.h _atoi64" c_atoi64 :: CString -> IO Int64-#else-foreign import ccall "stdlib.h strtoll" c_strtoll :: CString -> Ptr CString -> Int -> IO Int64-#endif--instance SqlBind a => SqlBind (Maybe a) where- fromSqlCStringLen fieldDef cstr cstrLen- | cstr == nullPtr = return Nothing- | otherwise = do v <- fromSqlCStringLen fieldDef cstr cstrLen- return (Just v)- - fromSqlValue tp s = Just (fromSqlValue tp s)-- toSqlValue (Just v) = toSqlValue v- toSqlValue Nothing = "null"--instance SqlBind Int where- fromSqlCStringLen (name,sqlType,_) cstr cstrLen- | cstr == nullPtr = throwDyn (SqlFetchNull name)- | sqlType==SqlInteger || - sqlType==SqlMedInt ||- sqlType==SqlTinyInt ||- sqlType==SqlSmallInt||- sqlType==SqlBigInt = c_atoi cstr- | otherwise = throwDyn (SqlBadTypeCast name sqlType)-- fromSqlValue SqlInteger s = Just (read s)- fromSqlValue SqlMedInt s = Just (read s)- fromSqlValue SqlTinyInt s = Just (read s)- fromSqlValue SqlSmallInt s = Just (read s)- fromSqlValue SqlBigInt s = Just (read s)- fromSqlValue SqlDouble s = Just (truncate (read s :: Double))- fromSqlValue SqlText s = Just (read s)- fromSqlValue _ _ = Nothing-- toSqlValue s = show s--instance SqlBind Int64 where- fromSqlCStringLen (name,sqlType,_) cstr cstrLen- | cstr == nullPtr = throwDyn (SqlFetchNull name)- | sqlType==SqlInteger ||- sqlType==SqlMedInt ||- sqlType==SqlTinyInt ||- sqlType==SqlSmallInt||- sqlType==SqlBigInt =-#ifdef mingw32_TARGET_OS- c_atoi64 cstr-#else- c_strtoll cstr nullPtr 10-#endif- | otherwise = throwDyn (SqlBadTypeCast name sqlType)-- fromSqlValue SqlInteger s = Just (read s)- fromSqlValue SqlMedInt s = Just (read s)- fromSqlValue SqlTinyInt s = Just (read s)- fromSqlValue SqlSmallInt s = Just (read s)- fromSqlValue SqlBigInt s = Just (read s)- fromSqlValue SqlDouble s = Just (truncate (read s :: Double))- fromSqlValue SqlText s = Just (read s)- fromSqlValue _ s = Nothing-- toSqlValue val = show val--instance SqlBind Integer where- fromSqlValue SqlInteger s = Just (read s)- fromSqlValue SqlMedInt s = Just (read s)- fromSqlValue SqlTinyInt s = Just (read s)- fromSqlValue SqlSmallInt s = Just (read s)- fromSqlValue SqlBigInt s = Just (read s)- fromSqlValue SqlDouble s = Just (truncate (read s :: Double))- fromSqlValue SqlText s = Just (read s)- fromSqlValue _ _ = Nothing-- toSqlValue s = show s-instance SqlBind String where- fromSqlValue _ = Just-- toSqlValue s = '\'' : foldr mapChar "'" s- where- mapChar '\\' s = '\\':'\\':s- mapChar '\'' s = '\\':'\'':s- mapChar '\n' s = '\\':'n' :s- mapChar '\r' s = '\\':'r' :s- mapChar '\t' s = '\\':'t' :s- mapChar '\NUL' s = '\\':'0' :s- mapChar c s = c :s--instance SqlBind Bool where- fromSqlValue SqlBit s = Just (s == "t")- fromSqlValue _ _ = Nothing-- toSqlValue True = "'t'"- toSqlValue False = "'f'"--instance SqlBind Double where- fromSqlValue (SqlDecimal _ _) s = Just (read s)- fromSqlValue (SqlNumeric _ _) s = Just (read s)- fromSqlValue SqlDouble s = Just (read s)- fromSqlValue SqlReal s = Just (read s)- fromSqlValue SqlFloat s = Just (read s)- fromSqlValue SqlText s = Just (read s)- fromSqlValue _ _ = Nothing-- toSqlValue d = show d--instance SqlBind Float where- fromSqlValue (SqlDecimal _ _) s = Just (read s)- fromSqlValue (SqlNumeric _ _) s = Just (read s)- fromSqlValue SqlDouble s = Just (read s)- fromSqlValue SqlReal s = Just (read s)- fromSqlValue SqlFloat s = Just (read s)- fromSqlValue SqlText s = Just (read s)- fromSqlValue _ _ = Nothing-- toSqlValue d = show d--mkClockTime :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> ClockTime-mkClockTime year mon mday hour min sec tz =- unsafePerformIO $ do- allocaBytes (#const sizeof(struct tm)) $ \ p_tm -> do- (#poke struct tm,tm_sec ) p_tm (fromIntegral sec :: CInt)- (#poke struct tm,tm_min ) p_tm (fromIntegral min :: CInt)- (#poke struct tm,tm_hour ) p_tm (fromIntegral hour :: CInt)- (#poke struct tm,tm_mday ) p_tm (fromIntegral mday :: CInt)- (#poke struct tm,tm_mon ) p_tm (fromIntegral (mon-1) :: CInt)- (#poke struct tm,tm_year ) p_tm (fromIntegral (year-1900) :: CInt)- (#poke struct tm,tm_isdst) p_tm (-1 :: CInt)- t <- mktime p_tm-#if __GLASGOW_HASKELL__ >= 603- return (TOD (fromIntegral (fromEnum t) + fromIntegral (tz-currTZ)) 0)-#else- return (TOD (fromIntegral t + fromIntegral (tz-currTZ)) 0)-#endif-foreign import ccall unsafe mktime :: Ptr () -> IO CTime--{-# NOINLINE currTZ #-}-currTZ :: Int-currTZ = ctTZ (unsafePerformIO (getClockTime >>= toCalendarTime)) -- Hack--parseTZ :: ReadP Int-parseTZ = (char '+' >> readDecP) `mplus` (char '-' >> fmap negate readDecP)--f_read :: ReadP a -> String -> Maybe a-f_read f s = case readP_to_S f s of {[(x,_)] -> Just x}--readHMS :: ReadP (Int, Int, Int)-readHMS = do- hour <- readDecP- char ':'- minutes <- readDecP- char ':'- seconds <- readDecP- return (hour, minutes, seconds)--readYMD :: ReadP (Int, Int, Int)-readYMD = do- year <- readDecP- char '-'- month <- readDecP- char '-'- day <- readDecP- return (year, month, day)--readDateTime :: ReadP (Int, Int, Int, Int, Int, Int)-readDateTime = do- (year, month, day) <- readYMD- skipSpaces- (hour, minutes, seconds) <- readHMS- return (year, month, day, hour, minutes, seconds)--instance SqlBind ClockTime where- fromSqlValue SqlTimeTZ s = f_read getTimeTZ s- where- getTimeTZ :: ReadP ClockTime- getTimeTZ = do- (hour, minutes, seconds) <- readHMS- (char '.' >> readDecP) `mplus` (return 0)- tz <- parseTZ- return (mkClockTime 1970 1 1 hour minutes seconds (tz*3600))-- fromSqlValue SqlTime s = f_read getTime s- where- getTime :: ReadP ClockTime- getTime = do- (hour, minutes, seconds) <- readHMS- return (mkClockTime 1970 1 1 hour minutes seconds currTZ)-- fromSqlValue SqlDate s = f_read getDate s- where- getDate :: ReadP ClockTime- getDate = do- (year, month, day) <- readYMD- return (mkClockTime year month day 0 0 0 currTZ)-- fromSqlValue SqlDateTimeTZ s = f_read getDateTimeTZ s- where- getDateTimeTZ :: ReadP ClockTime- getDateTimeTZ = do- (year, month, day, hour, minutes, seconds) <- readDateTime- char '.' >> readDecP -- ) `mplus` (return 0)- tz <- parseTZ- return (mkClockTime year month day hour minutes seconds (tz*3600))-- -- The only driver which seems to report the type as SqlTimeStamp seems- -- to be the MySQL driver. MySQL (at least 4.1) uses the same format for datetime and - -- timestamp columns.- -- Allow SqlText to support SQLite, which reports everything as SqlText- fromSqlValue t s | t == SqlDateTime || t == SqlTimeStamp || t == SqlText = f_read getDateTime s- where- getDateTime :: ReadP ClockTime- getDateTime = do- (year, month, day, hour, minutes, seconds) <- readDateTime- return (mkClockTime year month day hour minutes seconds currTZ)-- fromSqlValue _ _ = Nothing-- toSqlValue ct = '\'' : (shows (ctYear t) .- score .- shows (ctMonth t) .- score .- shows (ctDay t) .- space .- shows (ctHour t) .- colon .- shows (ctMin t) .- colon .- shows (ctSec t)) "'"- where- t = toUTCTime ct- score = showChar '-'- space = showChar ' '- colon = showChar ':'--data Point = Point Double Double deriving (Eq, Show)-data Line = Line Point Point deriving (Eq, Show)-data Path = OpenPath [Point] | ClosedPath [Point] deriving (Eq, Show)-data Box = Box Double Double Double Double deriving (Eq, Show)-data Circle = Circle Point Double deriving (Eq, Show)-data Polygon = Polygon [Point] deriving (Eq, Show)--instance SqlBind Point where- fromSqlValue SqlPoint s = case read s of- (x,y) -> Just (Point x y)- fromSqlValue _ _ = Nothing-- toSqlValue (Point x y) = '\'' : shows (x,y) "'"--instance SqlBind Line where- fromSqlValue SqlLSeg s = case read s of- [(x1,y1),(x2,y2)] -> Just (Line (Point x1 y1) (Point x2 y2))- fromSqlValue _ _ = Nothing-- toSqlValue (Line (Point x1 y1) (Point x2 y2)) = '\'' : shows [(x1,y1),(x2,y2)] "'"--instance SqlBind Path where- fromSqlValue SqlPath ('(':s) = case read ("["++init s++"]") of -- closed path- ps -> Just (ClosedPath (map (\(x,y) -> Point x y) ps))- fromSqlValue SqlPath s = case read s of -- closed path -- open path- ps -> Just (OpenPath (map (\(x,y) -> Point x y) ps))- fromSqlValue SqlLSeg s = case read s of- [(x1,y1),(x2,y2)] -> Just (OpenPath [(Point x1 y1), (Point x2 y2)])- fromSqlValue SqlPoint s = case read s of- (x,y) -> Just (ClosedPath [Point x y])- fromSqlValue _ _ = Nothing-- toSqlValue (OpenPath ps) = '\'' : shows ps "'"- toSqlValue (ClosedPath ps) = "'(" ++ init (tail (show ps)) ++ "')"--instance SqlBind Box where- fromSqlValue SqlBox s = case read ("("++s++")") of- ((x1,y1),(x2,y2)) -> Just (Box x1 y1 x2 y2)- fromSqlValue _ _ = Nothing-- toSqlValue (Box x1 y1 x2 y2) = '\'' : shows ((x1,y1),(x2,y2)) "'"--instance SqlBind Polygon where- fromSqlValue SqlPolygon s = case read ("["++init (tail s)++"]") of- ps -> Just (Polygon (map (\(x,y) -> Point x y) ps))- fromSqlValue _ _ = Nothing-- toSqlValue (Polygon ps) = "'(" ++ init (tail (show ps)) ++ "')"--instance SqlBind Circle where- fromSqlValue SqlCircle s = case read ("("++init (tail s)++")") of- ((x,y),r) -> Just (Circle (Point x y) r)- fromSqlValue _ _ = Nothing-- toSqlValue (Circle (Point x y) r) = "'<" ++ show (x,y) ++ "," ++ show r ++ "'>"--data INetAddr = INetAddr Int Int Int Int Int deriving (Eq,Show)--instance SqlBind INetAddr where- fromSqlValue t s- | t == SqlINetAddr || t == SqlCIDRAddr =- case readNum s of- (x1,s) -> case readNum s of- (x2,s) -> case readNum s of- (x3,s) -> case readNum s of- (x4,s) -> case readNum s of- (mask,_) -> Just (INetAddr x1 x2 x3 x4 mask)- | otherwise = Nothing- where- readNum s = case readDec s of- [(x,'.':s)] -> (x,s)- [(x,'/':s)] -> (x,s)- [(x,"")] -> (x,"")- _ -> (0,"")-- toSqlValue (INetAddr x1 x2 x3 x4 mask) = '\'' :- (shows x1 .- dot .- shows x2.- dot .- shows x3 .- dot .- shows x4 .- slash .- shows mask) "'"- where- dot = showChar '.'- slash = showChar '/'--data MacAddr = MacAddr Int Int Int Int Int Int deriving (Eq,Show)--instance SqlBind MacAddr where- fromSqlValue SqlMacAddr s =- case readHex s of- [(x1,':':s)] -> case readHex s of- [(x2,':':s)] -> case readHex s of- [(x3,':':s)] -> case readHex s of- [(x4,':':s)] -> case readHex s of- [(x5,':':s)] -> case readHex s of- [(x6,_)] -> Just (MacAddr x1 x2 x3 x4 x5 x6)- fromSqlValue _ _ = Nothing-- toSqlValue (MacAddr x1 x2 x3 x4 x5 x6) = '\'' :- (showHex x1 .- colon .- showHex x2 .- colon .- showHex x3 .- colon .- showHex x4 .- colon .- showHex x5 .- colon .- showHex x6) "'"- where- colon = showChar ':'- showHex = showIntAtBase 16 intToDigit---- | Retrieves the value of field with the specified name.-getFieldValue :: SqlBind a => Statement- -> String -- ^ Field name- -> IO a -- ^ Field value-getFieldValue stmt name = do- stmtGetCol stmt colNumber (name,sqlType,nullable) fromSqlCStringLen- where- (sqlType,nullable,colNumber) = findFieldInfo name (stmtFields stmt) 0--{-# DEPRECATED getFieldValueMB "Use getFieldValue instead." #-}-getFieldValueMB :: SqlBind a => Statement -> String -> IO (Maybe a)-getFieldValueMB = getFieldValue---- | Retrieves the value of field with the specified name.--- If the field value is @null@ then the function will return the default value.-getFieldValue' :: SqlBind a => Statement- -> String -- ^ Field name- -> a -- ^ Default field value- -> IO a -- ^ Field value-getFieldValue' stmt name def = do- mb_v <- getFieldValue stmt name- return (case mb_v of { Nothing -> def; Just a -> a })----------------------------------------------------------------------------------------------- helpers---------------------------------------------------------------------------------------------- | The 'forEachRow' function iterates through the result set in 'Statement' and--- executes the given action for each row in the set. The function closes the 'Statement'--- after the last row processing or if the given action raises an exception.-forEachRow :: (Statement -> s -> IO s) -- ^ an action- -> Statement -- ^ the statement- -> s -- ^ initial state- -> IO s -- ^ final state-forEachRow f stmt s = loop s `finally` closeStatement stmt- where- loop s = do- success <- fetch stmt- if success then f stmt s >>= loop else return s---- | The 'forEachRow\'' function is analogous to 'forEachRow' but doesn't provide state.--- The function closes the 'Statement' after the last row processing or if the given--- action raises an exception.-forEachRow' :: (Statement -> IO ()) -> Statement -> IO ()-forEachRow' f stmt = loop `finally` closeStatement stmt- where- loop = do- success <- fetch stmt- when success (f stmt >> loop)---- | The 'collectRows' function iterates through the result set in 'Statement' and--- executes the given action for each row in the set. The values returned from action--- are collected and returned as list. The function closes the 'Statement' after the--- last row processing or if the given action raises an exception.-collectRows :: (Statement -> IO a) -> Statement -> IO [a]-collectRows f stmt = loop `finally` closeStatement stmt- where- loop = do- success <- fetch stmt- if success- then do- x <- f stmt- xs <- loop- return (x:xs)- else return []
Database/HSQL/Types.hs view
@@ -1,153 +1,91 @@+{-# LANGUAGE RankNTypes #-} -- #hide-module Database.HSQL.Types where--import Control.Concurrent.MVar-import Control.Exception-import Data.Dynamic-import Foreign-import Foreign.C--type FieldDef = (String, SqlType, Bool)--data SqlType- = SqlChar Int -- ODBC, MySQL, PostgreSQL- | SqlVarChar Int -- ODBC, MySQL, PostgreSQL, MSI- | SqlLongVarChar Int -- ODBC- | SqlText -- , , PostgreSQL, MSI- | SqlWChar Int -- ODBC- | SqlWVarChar Int -- ODBC- | SqlWLongVarChar Int -- ODBC- | SqlDecimal Int Int -- ODBC- | SqlNumeric Int Int -- ODBC, MySQL, PostgreSQL- | SqlSmallInt -- ODBC, MySQL, PostgreSQL- | SqlMedInt -- , MySQL, - | SqlInteger -- ODBC, MySQL, PostgreSQL, MSI- | SqlReal -- ODBC, MySQL, PostgreSQL- | SqlFloat -- ODBC- | SqlDouble -- ODBC, MySQL, PostgreSQL- | SqlBit -- ODBC, , PostgreSQL- | SqlTinyInt -- ODBC, MySQL, PostgreSQL- | SqlBigInt -- ODBC, MySQL, PostgreSQL, MSI- | SqlBinary Int -- ODBC, , PostgreSQL- | SqlVarBinary Int -- ODBC, , PostgreSQL- | SqlLongVarBinary Int -- ODBC- | SqlDate -- ODBC, MySQL, PostgreSQL- | SqlTime -- ODBC, MySQL, PostgreSQL- | SqlTimeTZ -- , , PostgreSQL- | SqlAbsTime -- , , PostgreSQL- | SqlRelTime -- , , PostgreSQL- | SqlTimeInterval -- , , PostgreSQL- | SqlAbsTimeInterval -- , , PostgreSQL- | SqlTimeStamp -- ODBC, MySQL- | SqlDateTime -- , MySQL- | SqlDateTimeTZ -- , MySQL, PostgreSQL- | SqlYear -- , MySQL- | SqlSET -- , MySQL- | SqlENUM -- , MySQL- | SqlBLOB -- , MySQL, , MSI- | SqlMoney -- , , PostgreSQL- | SqlINetAddr -- , , PostgreSQL- | SqlCIDRAddr -- , , PostgreSQL- | SqlMacAddr -- , , PostgreSQL- | SqlPoint -- , , PostgreSQL- | SqlLSeg -- , , PostgreSQL- | SqlPath -- , , PostgreSQL- | SqlBox -- , , PostgreSQL- | SqlPolygon -- , , PostgreSQL- | SqlLine -- , , PostgreSQL- | SqlCircle -- , , PostgreSQL- | SqlUnknown Int -- ^ HSQL returns @SqlUnknown tp@ for all- -- columns for which it cannot determine- -- the right type. The @tp@ here is the- -- internal type code returned from the- -- backend library- deriving (Eq, Show)--data SqlError- = SqlError- { seState :: String- , seNativeError :: Int- , seErrorMsg :: String- }- | SqlNoData- | SqlInvalidHandle- | SqlStillExecuting- | SqlNeedData- | SqlBadTypeCast- { seFieldName :: String- , seFieldType :: SqlType- }- | SqlFetchNull- { seFieldName :: String- }- | SqlUnknownField- { seFieldName :: String- }- | SqlUnsupportedOperation- | SqlClosedHandle-#ifdef __GLASGOW_HASKELL__- deriving Typeable-#endif+{-| Basic type class & type definitions for DB interfacing.+-}+module Database.HSQL.Types+ (FieldDef,SqlType(..),SqlError(..),sqlErrorTc+ ,Connection(..),Statement(..),SqlBind(..)) where -sqlErrorTc :: TyCon-sqlErrorTc = mkTyCon "Database.HSQL.SqlError"+import Control.Concurrent.MVar(MVar)+import Control.Exception(throw)+import Foreign(nullPtr)+import Foreign.C(CString,peekCStringLen) -#ifndef __GLASGOW_HASKELL__-instance Typeable SqlError where- typeOf _ = mkAppTy sqlErrorTc []-#endif+import DB.HSQL.Type+import DB.HSQL.Error -instance Show SqlError where- showsPrec _ (SqlError{seErrorMsg=msg}) = showString msg- showsPrec _ SqlNoData = showString "No data"- showsPrec _ SqlInvalidHandle = showString "Invalid handle"- showsPrec _ SqlStillExecuting = showString "Stlll executing"- showsPrec _ SqlNeedData = showString "Need data"- showsPrec _ (SqlBadTypeCast name tp) = showString ("The type of " ++ name ++ " field can't be converted to " ++ show tp ++ " type")- showsPrec _ (SqlFetchNull name) = showString ("The value of " ++ name ++ " field is null")- showsPrec _ (SqlUnknownField name) = showString ("Unknown field name: " ++ name)- showsPrec _ SqlUnsupportedOperation = showString "Unsupported operation"- showsPrec _ SqlClosedHandle = showString "The referenced handle is already closed"+-- |+type FieldDef = (String, SqlType, Bool) --- | A 'Connection' type represents a connection to a database, through which you can operate on the it.--- In order to create the connection you need to use the @connect@ function from the module for--- your prefered backend.+-- | A 'Connection' type represents a connection to a database,+-- through which you can operate on the it.+-- In order to create the connection you need to use the @connect@ function+-- from the module for your prefered backend. data Connection- = Connection- { connDisconnect :: IO ()- , connExecute :: String -> IO ()- , connQuery :: String -> IO Statement- , connTables :: IO [String]- , connDescribe :: String -> IO [FieldDef]- , connBeginTransaction :: IO ()- , connCommitTransaction :: IO ()- , connRollbackTransaction :: IO ()- , connClosed :: MVar Bool- }+ = Connection {+ -- | disconnect action+ connDisconnect :: IO (),+ -- | query execution action (without return value)+ connExecute :: String -> IO (),+ -- | query action with return value+ connQuery :: String -> IO Statement,+ -- | retrieval of the names of the tables in reach+ connTables :: IO [String],+ -- | retrieval of the field defs of a table+ connDescribe :: String -> IO [FieldDef],+ -- | begin of a transaction+ connBeginTransaction :: IO (),+ -- | commit of a pending transaction+ connCommitTransaction :: IO (),+ -- | rollback of a pending transaction+ connRollbackTransaction :: IO (),+ -- | closing state of the connection+ connClosed :: MVar Bool } --- | The 'Statement' type represents a result from the execution of given SQL query.++-- | The 'Statement' type represents a result from the execution of given+-- SQL query. data Statement- = Statement- { stmtConn :: Connection- , stmtClose :: IO ()- , stmtFetch :: IO Bool- , stmtGetCol :: forall a . Int -> FieldDef -> (FieldDef -> CString -> Int -> IO a) -> IO a- , stmtFields :: [FieldDef]- , stmtClosed :: MVar Bool- }+ = Statement { + -- | field descriptors+ stmtConn :: Connection,+ -- | closing action+ stmtClose :: IO (),+ -- | incrementation of the row pointer and indication+ -- whether this is still in range of available rows+ stmtFetch :: IO Bool,+ -- | extraction of a field from the current result row, with+ -- + -- * a column index+ -- + -- * a column field definition+ -- + -- * a generic field extraction function, specifiable by+ -- a field definition, a C string and its length+ stmtGetCol :: forall a . Int -- column index+ -> FieldDef -- column field definition+ -> (FieldDef->CString->Int->IO a) + -- generic field extraction function,+ -- specifiable by field definition, + -- receiving the C string and its length+ -> IO a,+ -- | field descriptors+ stmtFields :: [FieldDef],+ -- | closing state of the statement+ stmtClosed :: MVar Bool } +-- | class SqlBind a where- -- This allows for faster conversion for eq. integral numeric types, etc.- -- Default version uses fromSqlValue.+ toSqlValue :: a -> String+ fromSqlValue :: SqlType -> String -> Maybe a+ -- | This allows for faster conversion for eq. integral numeric types,+ -- etc. Default version uses fromSqlValue. fromSqlCStringLen :: FieldDef -> CString -> Int -> IO a fromSqlCStringLen (name,sqlType,_) cstr cstrLen- | cstr == nullPtr = throwDyn (SqlFetchNull name)- | otherwise = do + | cstr == nullPtr = throw (SqlFetchNull name)+ | otherwise = do str <- peekCStringLen (cstr, cstrLen) case fromSqlValue sqlType str of- Nothing -> throwDyn (SqlBadTypeCast name sqlType)+ Nothing -> throw (SqlBadTypeCast name sqlType) Just v -> return v-- fromSqlValue :: SqlType -> String -> Maybe a- toSqlValue :: a -> String
hsql.cabal view
@@ -1,16 +1,25 @@ name: hsql-version: 1.7.1+version: 1.8.1 license: BSD3 author: Krasimir Angelov <ka2_mail@yahoo.com>-maintainer: Chris Done <chrisdone@gmail.com>+maintainer: Nick Rudnick <nick.rudnick@googlemail.com> category: Database synopsis: Simple library for database access from Haskell. description: Simple library for database access from Haskell. exposed-modules:+ DB.HSQL.Core,+ DB.HSQL.Error,+ DB.HSQL.Type,+ DB.HSQL.Type.Diverse,+ DB.HSQL.Type.Geometric,+ DB.HSQL.Type.Numeric,+ DB.HSQL.Type.Time,+ DB.HSQL.Type.NetAddress, Database.HSQL, Database.HSQL.Types-build-depends: base==3.*,old-time-extensions: ForeignFunctionInterface, TypeSynonymInstances, CPP, RankNTypes, DeriveDataTypeable+build-depends: base==4.*, old-time+extensions: CPP, ForeignFunctionInterface, DeriveDataTypeable, RankNTypes,+ ScopedTypeVariables build-type: Simple license-file: LICENSE cabal-version: >= 1.6