git.iko.soy/typeable/postgresql-simple
on master help sign in
Add support for isolation levels

Thanks to Philip Weaver for the suggestion

commitc77e3383e6fa346c2e0223bfb4fa65b7220b0e4e authorLeon P Smith <leon@melding-monads.com> dateThu 26 Jan 2012, 23:49 (15 years ago) parentf223ef4
1 file changed+39−18
src/Database/PostgreSQL/Simple.hs+39−18
src/Database/PostgreSQL/Simple.hs+39−18
@@ -85,8 +85,11 @@ module Database.PostgreSQL.Simple
8585-- , Base.insertID
8686 -- * Transaction handling
8787 , withTransaction
88+ , withTransactionLevel
89+ , IsolationLevel(..)
8890-- , Base.autocommit
8991 , begin
92+ , beginLevel
9093 , commit
9194 , rollback
9295 -- * Helper functions
@@ -332,12 +335,14 @@ data FetchQuantity
332335 = Automatic
333336 | Fixed !Int
334337
335−newtype FoldOptions
338+data FoldOptions
336339 = FoldOptions {
337− fetchQuantity :: FetchQuantity
340+ fetchQuantity :: !FetchQuantity,
341+ isolationLevel :: !IsolationLevel
338342 }
339343
340−defaultFoldOptions = FoldOptions { fetchQuantity = Automatic }
344+defaultFoldOptions = FoldOptions { fetchQuantity = Automatic
345+ , isolationLevel = ReadCommitted }
341346
342347foldWithOptions :: ( QueryResults row, QueryParams params )
343348 => FoldOptions
@@ -379,10 +384,10 @@ doFold :: ( QueryResults row )
379384 -> a
380385 -> (a -> row -> IO a)
381386 -> IO a
382−doFold opts conn _template q a f = do
387+doFold FoldOptions{..} conn _template q a f = do
383388 stat <- withConnection conn PQ.transactionStatus
384389 case stat of
385− PQ.TransIdle -> withTransaction conn go
390+ PQ.TransIdle -> withTransactionLevel isolationLevel conn go
386391 PQ.TransInTrans -> go
387392 PQ.TransActive -> fail "foldWithOpts FIXME: PQ.TransActive"
388393 -- This _shouldn't_ occur in the current incarnation of
@@ -409,7 +414,7 @@ doFold opts conn _template q a f = do
409414-- are of highly variable size.
410415-- A refinement of this technique is to pick this number adaptively
411416-- as results are read in from the database.
412− chunkSize = case fetchQuantity opts of
417+ chunkSize = case fetchQuantity of
413418 Automatic -> 256
414419 Fixed n -> n
415420 loop a = do
@@ -473,6 +478,17 @@ finishQuery conn q result = do
473478 , sqlErrorMsg = B.concat [ "query: ", statusmsg
474479 , ": ", errormsg ]}
475480
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+
476492-- | Execute an action inside a SQL transaction.
477493--
478494-- This function initiates a transaction with a \"@begin
@@ -484,8 +500,12 @@ finishQuery conn q result = do
484500-- PostgreSQL-related exception), the transaction will be rolled back using
485501-- 'rollback', then the exception will be rethrown.
486502withTransaction :: Connection -> IO a -> IO a
487−withTransaction conn act = do
488− _ <- begin conn
503+withTransaction = withTransactionLevel ReadCommitted
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
489509 r <- act `onException` rollback conn
490510 commit conn
491511 return r
@@ -493,22 +513,23 @@ withTransaction conn act = do
493513-- | Rollback a transaction.
494514-- rollback :: (MonadCatchIO m,MonadIO m) => Connection -> m ()
495515rollback :: Connection -> IO ()
496−rollback conn = do
497− _ <- execute_ conn "ABORT"
498− return ()
516+rollback conn = execute_ conn "ABORT" >> return ()
499517
500518-- | Commit a transaction.
501−-- commit :: (MonadCatchIO m,MonadIO m) => Connection -> m ()
502519commit :: Connection -> IO ()
503−commit conn = do
504− _ <- execute_ conn "COMMIT"
505− return ()
520+commit conn = execute_ conn "COMMIT" >> return ()
506521
507522-- | Begin a transaction.
508−-- begin :: (MonadCatchIO m,MonadIO m) => Connection -> m ()
509523begin :: Connection -> IO ()
510−begin conn = do
511− _ <- execute_ conn "BEGIN"
524+begin = beginLevel ReadCommitted
525+
526+-- | Begin a transaction with a given isolation level
527+beginLevel :: IsolationLevel -> Connection -> IO ()
528+beginLevel isolationLevel conn = do
529+ execute_ conn $! case isolationLevel of
530+ ReadCommitted -> "BEGIN"
531+ RepeatableRead -> "BEGIN ISOLATION LEVEL REPEATABLE READ"
532+ Serializable -> "BEGIN ISOLATION LEVEL SERIALIZABLE"
512533 return ()
513534
514535fmtError :: String -> Query -> [Action] -> a