git.iko.soy/typeable/postgresql-simple
on master help sign in
Add support for isolation levels
c77e338Leon P Smith
src/Database/PostgreSQL/Simple.hs+39−18
@@ -85,8 +85,11 @@ module Database.PostgreSQL.Simple
85-- , Base.insertID
85-- , Base.insertID
86 -- * Transaction handling
86 -- * Transaction handling
87 , withTransaction
87 , withTransaction
88+ , withTransactionLevel
89+ , IsolationLevel(..)
88-- , Base.autocommit
90-- , Base.autocommit
89 , begin
91 , begin
92+ , beginLevel
90 , commit
93 , commit
91 , rollback
94 , rollback
92 -- * Helper functions
95 -- * Helper functions
@@ -332,12 +335,14 @@ data FetchQuantity
332 = Automatic
335 = Automatic
333 | Fixed !Int
336 | Fixed !Int
334
337
335−newtype FoldOptions
338+data FoldOptions
336 = FoldOptions {
339 = FoldOptions {
337− fetchQuantity :: FetchQuantity
340+ fetchQuantity :: !FetchQuantity,
341+ isolationLevel :: !IsolationLevel
338 }
342 }
339
343
340−defaultFoldOptions = FoldOptions { fetchQuantity = Automatic }
344+defaultFoldOptions = FoldOptions { fetchQuantity = Automatic
345+ , isolationLevel = ReadCommitted }
341
346
342foldWithOptions :: ( QueryResults row, QueryParams params )
347foldWithOptions :: ( QueryResults row, QueryParams params )
343 => FoldOptions
348 => FoldOptions
@@ -379,10 +384,10 @@ doFold :: ( QueryResults row )
379 -> a
384 -> a
380 -> (a -> row -> IO a)
385 -> (a -> row -> IO a)
381 -> IO a
386 -> IO a
382−doFold opts conn _template q a f = do
387+doFold FoldOptions{..} conn _template q a f = do
383 stat <- withConnection conn PQ.transactionStatus
388 stat <- withConnection conn PQ.transactionStatus
384 case stat of
389 case stat of
385− PQ.TransIdle -> withTransaction conn go
390+ PQ.TransIdle -> withTransactionLevel isolationLevel conn go
386 PQ.TransInTrans -> go
391 PQ.TransInTrans -> go
387 PQ.TransActive -> fail "foldWithOpts FIXME: PQ.TransActive"
392 PQ.TransActive -> fail "foldWithOpts FIXME: PQ.TransActive"
388 -- This _shouldn't_ occur in the current incarnation of
393 -- This _shouldn't_ occur in the current incarnation of
@@ -409,7 +414,7 @@ doFold opts conn _template q a f = do
409-- are of highly variable size.
414-- are of highly variable size.
410-- A refinement of this technique is to pick this number adaptively
415-- A refinement of this technique is to pick this number adaptively
411-- as results are read in from the database.
416-- as results are read in from the database.
412− chunkSize = case fetchQuantity opts of
417+ chunkSize = case fetchQuantity of
413 Automatic -> 256
418 Automatic -> 256
414 Fixed n -> n
419 Fixed n -> n
415 loop a = do
420 loop a = do
@@ -473,6 +478,17 @@ finishQuery conn q result = do
473 , sqlErrorMsg = B.concat [ "query: ", statusmsg
478 , sqlErrorMsg = B.concat [ "query: ", statusmsg
474 , ": ", errormsg ]}
479 , ": ", errormsg ]}
475
480
481+-- | Of the four isolation levels defined by the SQL standard,
482+-- these are the three levels distinguished by PostgreSQL as of version 9.0.
483+-- See <http://www.postgresql.org/docs/9.1/static/transaction-iso.html>
484+-- for more information.
485+
486+data IsolationLevel
487+ = ReadCommitted
488+ | RepeatableRead
489+ | Serializable
490+ deriving (Show, Eq, Ord, Enum, Bounded)
491+
476-- | Execute an action inside a SQL transaction.
492-- | Execute an action inside a SQL transaction.
477--
493--
478-- This function initiates a transaction with a \"@begin
494-- This function initiates a transaction with a \"@begin
@@ -484,8 +500,12 @@ finishQuery conn q result = do
484-- PostgreSQL-related exception), the transaction will be rolled back using
500-- PostgreSQL-related exception), the transaction will be rolled back using
485-- 'rollback', then the exception will be rethrown.
501-- 'rollback', then the exception will be rethrown.
486withTransaction :: Connection -> IO a -> IO a
502withTransaction :: Connection -> IO a -> IO a
487−withTransaction conn act = do
503+withTransaction = withTransactionLevel ReadCommitted
488− _ <- begin conn
504+
505+-- | Execute an action inside a SQL transaction with a given isolation level.
506+withTransactionLevel :: IsolationLevel -> Connection -> IO a -> IO a
507+withTransactionLevel isolationLevel conn act = do
508+ beginLevel isolationLevel conn
489 r <- act `onException` rollback conn
509 r <- act `onException` rollback conn
490 commit conn
510 commit conn
491 return r
511 return r
@@ -493,22 +513,23 @@ withTransaction conn act = do
493-- | Rollback a transaction.
513-- | Rollback a transaction.
494-- rollback :: (MonadCatchIO m,MonadIO m) => Connection -> m ()
514-- rollback :: (MonadCatchIO m,MonadIO m) => Connection -> m ()
495rollback :: Connection -> IO ()
515rollback :: Connection -> IO ()
496−rollback conn = do
497− _ <- execute_ conn "ABORT"
516+rollback conn = execute_ conn "ABORT" >> return ()
498− return ()
499
517
500-- | Commit a transaction.
518-- | Commit a transaction.
501−-- commit :: (MonadCatchIO m,MonadIO m) => Connection -> m ()
502commit :: Connection -> IO ()
519commit :: Connection -> IO ()
503−commit conn = do
504− _ <- execute_ conn "COMMIT"
520+commit conn = execute_ conn "COMMIT" >> return ()
505− return ()
506
521
507-- | Begin a transaction.
522-- | Begin a transaction.
508−-- begin :: (MonadCatchIO m,MonadIO m) => Connection -> m ()
509begin :: Connection -> IO ()
523begin :: Connection -> IO ()
510−begin conn = do
524+begin = beginLevel ReadCommitted
525+
526+-- | Begin a transaction with a given isolation level
527+beginLevel :: IsolationLevel -> Connection -> IO ()
528+beginLevel isolationLevel conn = do
511− _ <- execute_ conn "BEGIN"
529+ execute_ conn $! case isolationLevel of
530+ ReadCommitted -> "BEGIN"
531+ RepeatableRead -> "BEGIN ISOLATION LEVEL REPEATABLE READ"
532+ Serializable -> "BEGIN ISOLATION LEVEL SERIALIZABLE"
512 return ()
533 return ()
513
534
514fmtError :: String -> Query -> [Action] -> a
535fmtError :: String -> Query -> [Action] -> a