hsSqlite3-0.1: src/Database/Sqlite3/Middle.hs
module Database.Sqlite3.Middle where
import Bindings.Sqlite3
import qualified Data.ByteString as B
import Codec.Binary.UTF8.String
import Control.Monad.Error
import Foreign.C hiding (newCString)
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import Foreign.Ptr
import Foreign.Storable
type Db a = (DbError e, MonadError e m, MonadDb m) => m a
class DbError e where
makeErr :: CInt -> e
castErr :: e -> Maybe CInt
class MonadIO m => MonadDb m where
getDb :: m (Ptr C'sqlite3)
putDb :: Ptr C'sqlite3 -> m ()
cleanDb :: m ()
isDbReady :: m Bool
getSt :: m (Ptr C'sqlite3_stmt)
putSt :: Ptr C'sqlite3_stmt -> m ()
cleanSt :: m ()
isStReady :: m Bool
open :: String -> Db ()
open path = do
cpath <- liftIO $ newCString path
db' <- liftIO $ malloc
rc <- liftIO $ c'sqlite3_open cpath db'
db <- liftIO $ peek db'
putDb db
liftIO $ free db'
err rc
close :: Db ()
close = do
db <- getDb
rc <- liftIO $ c'sqlite3_close db
cleanDb
err rc
prepare :: String -> Db ()
prepare sql = do
cstr <- liftIO $ newCString sql
let len = toEnum $ length sql
st' <- liftIO $ malloc
db <- getDb
rc <- liftIO $ c'sqlite3_prepare db cstr len st' nullPtr
st <- liftIO $ peek st'
putSt st
liftIO $ free st'
err rc
finalize :: Db ()
finalize = do
st <- getSt
rc <- liftIO $ c'sqlite3_finalize st
cleanSt
err rc
reset :: Db ()
reset = do
st <- getSt
rc <- liftIO $ c'sqlite3_reset st
err rc
step :: Db Bool
step = do
st <- getSt
rc <- liftIO $ c'sqlite3_step st
case rc of
100 -> return False
101 -> return True
_ -> throwError (makeErr rc)
bindInt :: Int -> Int -> Db ()
bindInt num val = do
st <- getSt
rc <- liftIO $ c'sqlite3_bind_int st (toEnum num) (toEnum val)
err rc
bindDouble :: Int -> Double -> Db ()
bindDouble num val = do
st <- getSt
rc <- liftIO $ c'sqlite3_bind_double st (toEnum num) (realToFrac val)
err rc
bindText :: Int -> String -> Db ()
bindText num val = do
cstr <- liftIO $ newCString val
let len = toEnum $ length val
st <- getSt
rc <- liftIO $ c'sqlite3_bind_text st (toEnum num) cstr len nullFunPtr
err rc
columnBytes :: Int -> Db Int
columnBytes num = do
st <- getSt
cint <- liftIO $ c'sqlite3_column_bytes st (toEnum num)
return (fromEnum cint)
columnCount :: Db Int
columnCount = do
st <- getSt
cint <- liftIO $ c'sqlite3_column_count st
return (fromEnum cint)
columnInt :: Int -> Db Int
columnInt num = do
st <- getSt
cint <- liftIO $ c'sqlite3_column_int st (toEnum num)
return (fromEnum cint)
columnType :: Int -> Db Int
columnType num = do
st <- getSt
cint <- liftIO $ c'sqlite3_column_type st (toEnum num)
return (fromEnum cint)
columnDouble :: Int -> Db Double
columnDouble num = do
st <- getSt
x <- liftIO $ c'sqlite3_column_double st (toEnum num)
return (realToFrac x)
columnBlob :: Int -> Db B.ByteString
columnBlob num = do
st <- getSt
by <- columnBytes num
bl <- liftIO $ c'sqlite3_column_blob st (toEnum num)
liftIO $ B.packCStringLen (castPtr bl,by)
errorHook x = catchError x hook where
hook e = do
ignore finalize
ignore close
throwError e
ignore x = catchError (x >> return ()) (const $ return ())
newCString :: String -> IO CString
newCString = newArray0 0 . map fromIntegral . encode
err :: CInt -> Db ()
err 0 = return ()
err x = throwError (makeErr x)