mysql-haskell 0.4.0.0 → 0.4.1.0
raw patch · 6 files changed
+85/−26 lines, 6 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Database.MySQL.BinLog: RowDeleteEvent :: !Word32 -> !BinLogTracker -> !TableMapEvent -> !DeleteRowsEvent -> RowBinLogEvent
+ Database.MySQL.BinLog: RowDeleteEvent :: {-# UNPACK #-} !Word32 -> !BinLogTracker -> !TableMapEvent -> !DeleteRowsEvent -> RowBinLogEvent
- Database.MySQL.BinLog: RowQueryEvent :: !Word32 -> !BinLogTracker -> !QueryEvent' -> RowBinLogEvent
+ Database.MySQL.BinLog: RowQueryEvent :: {-# UNPACK #-} !Word32 -> !BinLogTracker -> !QueryEvent' -> RowBinLogEvent
- Database.MySQL.BinLog: RowUpdateEvent :: !Word32 -> !BinLogTracker -> !TableMapEvent -> !UpdateRowsEvent -> RowBinLogEvent
+ Database.MySQL.BinLog: RowUpdateEvent :: {-# UNPACK #-} !Word32 -> !BinLogTracker -> !TableMapEvent -> !UpdateRowsEvent -> RowBinLogEvent
- Database.MySQL.BinLog: RowWriteEvent :: !Word32 -> !BinLogTracker -> !TableMapEvent -> !WriteRowsEvent -> RowBinLogEvent
+ Database.MySQL.BinLog: RowWriteEvent :: {-# UNPACK #-} !Word32 -> !BinLogTracker -> !TableMapEvent -> !WriteRowsEvent -> RowBinLogEvent
Files
- Database/MySQL/Base.hs +5/−5
- Database/MySQL/BinLog.hs +6/−6
- Database/MySQL/BinLogProtocol/BinLogValue.hs +5/−5
- Database/MySQL/Connection.hs +8/−8
- README.md +60/−1
- mysql-haskell.cabal +1/−1
Database/MySQL/Base.hs view
@@ -149,15 +149,15 @@ else do StmtPrepareOK stid colCnt paramCnt _ <- getFromPacket getStmtPrepareOK p _ <- replicateM_ paramCnt (readPacket is)- _ <- unless (colCnt == 0) (void (readPacket is)) -- EOF- _ <- replicateM_ colCnt (readPacket is) _ <- unless (paramCnt == 0) (void (readPacket is)) -- EOF+ _ <- replicateM_ colCnt (readPacket is)+ _ <- unless (colCnt == 0) (void (readPacket is)) -- EOF return stid -- | Ask MySQL to prepare a query statement. -- -- All details from @COM_STMT_PREPARE@ Response are returned: the 'StmtPrepareOK' packet,--- params's 'ColumnDef', table's 'ColumnDef'.+-- params's 'ColumnDef', result's 'ColumnDef'. -- prepareStmtDetail :: MySQLConn -> Query -> IO (StmtPrepareOK, [ColumnDef], [ColumnDef]) prepareStmtDetail conn@(MySQLConn is os _ _) (Query stmt) = do@@ -169,9 +169,9 @@ else do sOK@(StmtPrepareOK _ colCnt paramCnt _) <- getFromPacket getStmtPrepareOK p pdefs <- replicateM paramCnt ((decodeFromPacket <=< readPacket) is)- _ <- unless (colCnt == 0) (void (readPacket is)) -- EOF- cdefs <- replicateM colCnt ((decodeFromPacket <=< readPacket) is) _ <- unless (paramCnt == 0) (void (readPacket is)) -- EOF+ cdefs <- replicateM colCnt ((decodeFromPacket <=< readPacket) is)+ _ <- unless (colCnt == 0) (void (readPacket is)) -- EOF return (sOK, pdefs, cdefs) -- | Ask MySQL to closed a query statement.
Database/MySQL/BinLog.hs view
@@ -124,22 +124,22 @@ | isEOF p -> return Nothing | isERR p -> decodeFromPacket p >>= throwIO . ERRException --- | Row based biblog event type.+-- | Row based binlog event type. -- -- It's recommended to enable row query event before 'dumpBinLog', so that you can get -- 'RowQueryEvent' in row based binlog(it's important for detect a table change for example), -- more information please refer <http://dev.mysql.com/doc/refman/5.7/en/replication-options-binary-log.html#sysvar_binlog_rows_query_log_events sysvar_binlog_rows_query_log_events> ----- a 'BinLogTracker' is included so that you can roll up your own HA solutions,+-- A 'BinLogTracker' is included so that you can roll up your own HA solutions, -- for example, writing the tracker to zookeeper when you done with an event. -- -- The first 'Word32' field is a timestamp present when this event is logged. -- data RowBinLogEvent- = RowQueryEvent !Word32 !BinLogTracker !QueryEvent'- | RowDeleteEvent !Word32 !BinLogTracker !TableMapEvent !DeleteRowsEvent- | RowWriteEvent !Word32 !BinLogTracker !TableMapEvent !WriteRowsEvent- | RowUpdateEvent !Word32 !BinLogTracker !TableMapEvent !UpdateRowsEvent+ = RowQueryEvent {-# UNPACK #-} !Word32 !BinLogTracker !QueryEvent'+ | RowDeleteEvent {-# UNPACK #-} !Word32 !BinLogTracker !TableMapEvent !DeleteRowsEvent+ | RowWriteEvent {-# UNPACK #-} !Word32 !BinLogTracker !TableMapEvent !WriteRowsEvent+ | RowUpdateEvent {-# UNPACK #-} !Word32 !BinLogTracker !TableMapEvent !UpdateRowsEvent deriving (Show, Eq, Generic) -- | decode row based event from 'BinLogPacket' stream.
Database/MySQL/BinLogProtocol/BinLogValue.hs view
@@ -11,7 +11,6 @@ -} - module Database.MySQL.BinLogProtocol.BinLogValue where import Control.Applicative@@ -47,7 +46,8 @@ -- see 'MySQLVaule' 's note. -- -- There's also no infomation about charset, so we use 'ByteString' to present both text--- and blob types.+-- and blob types, if you want to get text representation back, you have to query column charset+-- infomation, and use icu or iconv to decode. IT MAY NOT BE UTF-8. -- -- The @SET@ and @ENUM@ values are presented by their index's value and bitmap respectively, -- if you need get the string value back, you have to perform a 'DESC tablename' to get the@@ -93,7 +93,7 @@ getBinLogField (BINLOG_TYPE_BIT _ bytes) = BinLogBit <$> getBits' bytes getBinLogField BINLOG_TYPE_TIMESTAMP = BinLogTimeStamp <$> getWord32le --- ^ a integer in @YYYYMMDD@ format, for example:+-- A integer in @YYYYMMDD@ format, for example: -- 99991231 stand for @9999-12-31@ getBinLogField BINLOG_TYPE_DATE = do i <- getWord24le@@ -108,7 +108,7 @@ ms <- fromIntegral <$> getMicroSecond fsp pure (BinLogTimeStamp2 s ms) --- a integer in @YYYYMMDDhhmmss@, for example:+-- A integer in @YYYYMMDDhhmmss@, for example: -- 99991231235959 stand for @9999-12-31 23:59:59@ getBinLogField BINLOG_TYPE_DATETIME = do i <- getWord64le@@ -149,7 +149,7 @@ ms <- fromIntegral <$> getMicroSecond fsp pure (BinLogDateTime2 yyyy' mm' dd h m s ms) --- ^ a integer in @hhmmss@ format(can be negative), for example:+-- A integer in @hhmmss@ format(can be negative), for example: -- 8385959 stand for @838:59:59@ getBinLogField BINLOG_TYPE_TIME = do i <- getWord24le
Database/MySQL/Connection.hs view
@@ -48,7 +48,7 @@ -- | Everything you need to establish a MySQL connection. ----- You may want some helpers in "System.IO.Streams.TLS" to setup TLS connection.+-- To setup a TLS connection, use module "Database.MySQL.TLS" or "Database.MySQL.OpenSSL". -- data ConnectInfo = ConnectInfo { ciHost :: HostName@@ -104,10 +104,10 @@ in Auth clientCap clientMaxPacketSize clientCharset user scambleBuf db where scramble :: ByteString -> ByteString -> ByteString- scramble salt pass- | B.null pass = B.empty+ scramble salt pass'+ | B.null pass' = B.empty | otherwise = B.pack (B.zipWith xor sha1pass withSalt)- where sha1pass = sha1 pass+ where sha1pass = sha1 pass' withSalt = sha1 (salt `B.append` sha1 sha1pass) sha1 :: ByteString -> ByteString@@ -125,18 +125,18 @@ return . Just $ Packet len seqN body where loopRead acc 0 _ = return $! L.fromChunks (reverse acc)- loopRead acc k is = do- bs <- Stream.read is+ loopRead acc k is' = do+ bs <- Stream.read is' case bs of Nothing -> throwIO NetworkException Just bs' -> do let l = fromIntegral (B.length bs') if l >= k then do let (a, rest) = B.splitAt (fromIntegral k) bs'- unless (B.null rest) (Stream.unRead rest is)+ unless (B.null rest) (Stream.unRead rest is') return $! L.fromChunks (reverse (a:acc)) else do let k' = k - l- k' `seq` loopRead (bs':acc) k' is+ k' `seq` loopRead (bs':acc) k' is' -- | Close a MySQL connection. --
README.md view
@@ -11,7 +11,7 @@ Is it fast? ---------- -In short, `select`(decode) is about 2 times slower than pure c/c++, `insert` (encode) is about 1.5 times slower than pure c/c++, there're many factors involved(tls, prepared statment, batch using multiple statement):+In short, `select`(decode) is about 2 times slower than pure c/c++ but 5 times faster than `mysql-simple`, `insert` (encode) is about 1.5 times slower than pure c/c++, there're many factors involved(tls, prepared statment, batch using multiple statement): <img src="https://github.com/winterland1989/mysql-haskell/blob/master/benchmark/result.png?raw=true" width="100%"> @@ -34,6 +34,65 @@ + no replication protocol support. `mysql-haskell` is intended to solve these problems, and provide foundation for higher level libraries such as groundhog and persistent, so that accessing MySQL is both fast and easy in haskell.++Guide+-----++The `Database.MySQL.Base` module provides everything you need to start making queries:++```haskell+{-# LANGUAGE OverloadedStrings #-}++module Main where++import Database.MySQL.Base+import qualified System.IO.Streams as Streams++main :: IO () +main = do+ conn <- connect+ defaultConnectInfo {ciUser = "username", ciPassword = "password", ciDatabase = "dbname"}+ (defs, is) <- query_ conn "SELECT * FROM some_table"+ print =<< Streams.toList is+```++`query/query_` will return a column definition list, and an `InputStream` of rows, you should consume this stream completely before start new queries.++It's recommanded to use prepared statement to improve query speed:++```haskell+ ...+ s <- prepareStmt conn "SELECT * FROM some_table where person_age > ?"+ ...+ (defs, is) <- queryStmt s [MySQLInt32U 18]+ ...+```++If you want to do batch inserting/deleting/updating, you can use `executeMany` to save considerable time.++The `Database.MySQL.BinLog` module provides binlog listenning functions and row-based event decoder, following program will automatically get last binlog position, and print every row event it receives:++```haskell+{-# LANGUAGE LambdaCase #-}+module Main where++import Control.Monad (forever)+import qualified Database.MySQL.BinLog as MySQL+import qualified System.IO.Streams as Streams++main :: IO () +main = do+ conn <- MySQL.connect + MySQL.defaultConnectInfo {ciUser = "username", ciPassword = "password", ciDatabase = "dbname"}+ MySQL.getLastBinLogTracker conn >>= \ case+ Just tracker -> do+ es <- MySQL.decodeRowBinLogEvent =<< MySQL.dumpBinLog conn 1024 tracker False+ forever $ do+ Streams.read es >>= \ case+ Just v -> print v+ Nothing -> return ()+ Nothing -> error "can't get latest binlog position"+``` Build Test Benchmark --------------------
mysql-haskell.cabal view
@@ -1,5 +1,5 @@ name: mysql-haskell-version: 0.4.0.0+version: 0.4.1.0 synopsis: pure haskell MySQL driver description: pure haskell MySQL driver license: BSD3