postgresql-simple-0.2.4.1: Mid-Level PostgreSQL client library

Portability | portable
Stability | experimental
Maintainer | Leon P Smith <leon@melding-monads.com>
Safe Haskell | None

Database.PostgreSQL.Simple

Contents

- Writing queries
  - The Query type
  - Parameter substitution
    - Type inference
  - Substituting a single parameter
  - Representing a list of values
  - Modifying multiple rows at once
  - `RETURNING`: modifications that returns results
- Extracting results
  - Handling null values
  - Type conversions
- Types
  - Exceptions
- Connection management
- Queries that return results
- Queries that stream results
- Statements that do not return results
- Transaction handling
- Helper functions

Description

A mid-level client library for the PostgreSQL database, aimed at ease of use and high performance.

Synopsis

- data ConnectInfo = ConnectInfo {
  - connectHost :: String
  - connectPort :: Word16
  - connectUser :: String
  - connectPassword :: String
  - connectDatabase :: String
  }
- data Connection
- data Query
- class ToRow a
- class FromRow a
- newtype In a = In a
- newtype Binary a = Binary a
- newtype Only a = Only {
  - fromOnly :: a
  }
- data h :. t = h :. t
- data SqlError = SqlError {
  - sqlState :: ByteString
  - sqlNativeError :: Int
  - sqlErrorMsg :: ByteString
  }
- data FormatError
- data QueryError
- data ResultError
- connect :: ConnectInfo -> IO Connection
- connectPostgreSQL :: ByteString -> IO Connection
- postgreSQLConnectionString :: ConnectInfo -> ByteString
- defaultConnectInfo :: ConnectInfo
- close :: Connection -> IO ()
- query :: (ToRow q, FromRow r) => Connection -> Query -> q -> IO [r]
- query_ :: FromRow r => Connection -> Query -> IO [r]
- data FoldOptions = FoldOptions {
  - fetchQuantity :: !FetchQuantity
  - transactionMode :: !TransactionMode
  }
- data FetchQuantity
  - = Automatic
  - | Fixed !Int
- defaultFoldOptions :: FoldOptions
- fold :: (FromRow row, ToRow params) => Connection -> Query -> params -> a -> (a -> row -> IO a) -> IO a
- foldWithOptions :: (FromRow row, ToRow params) => FoldOptions -> Connection -> Query -> params -> a -> (a -> row -> IO a) -> IO a
- fold_ :: FromRow r => Connection -> Query -> a -> (a -> r -> IO a) -> IO a
- foldWithOptions_ :: FromRow r => FoldOptions -> Connection -> Query -> a -> (a -> r -> IO a) -> IO a
- forEach :: (ToRow q, FromRow r) => Connection -> Query -> q -> (r -> IO ()) -> IO ()
- forEach_ :: FromRow r => Connection -> Query -> (r -> IO ()) -> IO ()
- returning :: (ToRow q, FromRow r) => Connection -> Query -> [q] -> IO [r]
- execute :: ToRow q => Connection -> Query -> q -> IO Int64
- execute_ :: Connection -> Query -> IO Int64
- executeMany :: ToRow q => Connection -> Query -> [q] -> IO Int64
- withTransaction :: Connection -> IO a -> IO a
- withTransactionSerializable :: Connection -> IO a -> IO a
- data TransactionMode = TransactionMode {
  - isolationLevel :: !IsolationLevel
  - readWriteMode :: !ReadWriteMode
  }
- data IsolationLevel
  - = DefaultIsolationLevel
  - | ReadCommitted
  - | RepeatableRead
  - | Serializable
- data ReadWriteMode
  - = DefaultReadWriteMode
  - | ReadWrite
  - | ReadOnly
- defaultTransactionMode :: TransactionMode
- defaultIsolationLevel :: IsolationLevel
- defaultReadWriteMode :: ReadWriteMode
- withTransactionLevel :: IsolationLevel -> Connection -> IO a -> IO a
- withTransactionMode :: TransactionMode -> Connection -> IO a -> IO a
- withTransactionModeRetry :: TransactionMode -> Connection -> IO a -> IO a
- begin :: Connection -> IO ()
- beginLevel :: IsolationLevel -> Connection -> IO ()
- beginMode :: TransactionMode -> Connection -> IO ()
- commit :: Connection -> IO ()
- rollback :: Connection -> IO ()
- formatMany :: ToRow q => Connection -> Query -> [q] -> IO ByteString
- formatQuery :: ToRow q => Connection -> Query -> q -> IO ByteString

# Writing queries

SQL-based applications are somewhat notorious for their susceptibility to attacks through the injection of maliciously crafted data. The primary reason for widespread vulnerability to SQL injections is that many applications are sloppy in handling user data when constructing SQL queries.

This library provides a `Query` type and a parameter substitution facility to address both ease of use and security.

## The Query type

A `Query` is a `newtype`-wrapped `ByteString`. It intentionally exposes a tiny API that is not compatible with the `ByteString` API; this makes it difficult to construct queries from fragments of strings. The `query` and `execute` functions require queries to be of type `Query`.

To most easily construct a query, enable GHC's `OverloadedStrings` language extension and write your query as a normal literal string.

     {-# LANGUAGE OverloadedStrings #-}

     import Database.PostgreSQL.Simple

     hello = do
       conn <- connect defaultConnectInfo
       query conn "select 2 + 2"

A `Query` value does not represent the actual query that will be executed, but is a template for constructing the final query.

## Parameter substitution

Since applications need to be able to construct queries with parameters that change, this library provides a query substitution capability.

The `Query` template accepted by `query` and `execute` can contain any number of "`?`" characters. Both `query` and `execute` accept a third argument, typically a tuple. When constructing the real query to execute, these functions replace the first "`?`" in the template with the first element of the tuple, the second "`?`" with the second element, and so on. If necessary, each tuple element will be quoted and escaped prior to substitution; this defeats the single most common injection vector for malicious data.

For example, given the following `Query` template:

     select * from user where first_name = ? and age > ?

And a tuple of this form:

     ("Boris" :: String, 37 :: Int)

The query to be executed will look like this after substitution:

     select * from user where first_name = 'Boris' and age > 37

If there is a mismatch between the number of "`?`" characters in your template and the number of elements in your tuple, a `FormatError` will be thrown.

Note that the substitution functions do not attempt to parse or validate your query. It's up to you to write syntactically valid SQL, and to ensure that each "`?`" in your query template is matched with the right tuple element.

### Type inference

Automated type inference means that you will often be able to avoid supplying explicit type signatures for the elements of a tuple. However, sometimes the compiler will not be able to infer your types. Consider a case where you write a numeric literal in a parameter tuple:

     query conn "select ? + ?" (40,2)

The above query will be rejected by the compiler, because it does not know the specific numeric types of the literals `40` and `2`. This is easily fixed:

     query conn "select ? + ?" (40 :: Double, 2 :: Double)

The same kind of problem can arise with string literals if you have the `OverloadedStrings` language extension enabled. Again, just use an explicit type signature if this happens.

## Substituting a single parameter

Haskell lacks a single-element tuple type, so if you have just one value you want substituted into a query, what should you do?

The obvious approach would appear to be something like this:

     instance (Param a) => QueryParam a where
         ...

Unfortunately, this wreaks havoc with type inference, so we take a different tack. To represent a single value `val` as a parameter, write a singleton list `[val]`, use `Just` `val`, or use `Only` `val`.

Here's an example using a singleton list:

     execute conn "insert into users (first_name) values (?)"
                  ["Nuala"]

## Representing a list of values

Suppose you want to write a query using an `IN` clause:

     select * from users where first_name in ('Anna', 'Boris', 'Carla')

In such cases, it's common for both the elements and length of the list after the `IN` keyword to vary from query to query.

To address this case, use the `In` type wrapper, and use a single "`?`" character to represent the list. Omit the parentheses around the list; these will be added for you.

Here's an example:

     query conn "select * from users where first_name in ?" $
           In ["Anna", "Boris", "Carla"]

If your `In`-wrapped list is empty, the string `"(null)"` will be substituted instead, to ensure that your clause remains syntactically valid.

## Modifying multiple rows at once

If you know that you have many rows of data to insert into a table, it is much more efficient to perform all the insertions in a single multi-row `INSERT` statement than individually.

The `executeMany` function is intended specifically for helping with multi-row `INSERT` and `UPDATE` statements. Its rules for query substitution are different than those for `execute`.

What `executeMany` searches for in your `Query` template is a single substring of the form:

     values (?,?,?)

The rules are as follows:

- The keyword `VALUES` is matched case insensitively.
- There must be no other "`?`" characters anywhere in your template.
- There must one or more "`?`" in the parentheses.
- Extra white space is fine.

The last argument to `executeMany` is a list of parameter tuples. These will be substituted into the query where the `(?,?)` string appears, in a form suitable for use in a multi-row `INSERT` or `UPDATE`.

Here is an example:

     executeMany conn
       "insert into users (first_name,last_name) values (?,?)"
       [("Boris","Karloff"),("Ed","Wood")]

The query that will be executed here will look like this (reformatted for tidiness):

     insert into users (first_name,last_name) values
       ('Boris','Karloff'),('Ed','Wood')

## `RETURNING`: modifications that returns results

The `returning` function is similar to `executeMany` but is intended for use with multi-tuple `INSERT` or `UPDATE` statements that make use of `RETURNING`.

For example, were there an auto-incrementing `id` column and timestamp column `t` that defaulted to the present time for the `sales` table, then the following query would insert two new sales records and also return their new `id`s and timestamps.

     let q = "insert into sales (amount, label) values (?,?) returning id, t"
     xs :: [(Int, UTCTime)] <- returning conn q [(20,"Chips"),(300,"Wood")]

# Extracting results

The `query` and `query_` functions return a list of values in the `FromRow` typeclass. This class performs automatic extraction and type conversion of rows from a query result.

Here is a simple example of how to extract results:

     import qualified Data.Text as Text

     xs <- query_ conn "select name,age from users"
     forM_ xs $ \(name,age) ->
       putStrLn $ Text.unpack name ++ " is " ++ show (age :: Int)

Notice two important details about this code:

- The number of columns we ask for in the query template must exactly match the number of elements we specify in a row of the result tuple. If they do not match, a `ResultError` exception will be thrown.
- Sometimes, the compiler needs our help in specifying types. It can infer that `name` must be a `Text`, due to our use of the `unpack` function. However, we have to tell it the type of `age`, as it has no other information to determine the exact type.

## Handling null values

The type of a result tuple will look something like this:

     (Text, Int, Int)

Although SQL can accommodate `NULL` as a value for any of these types, Haskell cannot. If your result contains columns that may be `NULL`, be sure that you use `Maybe` in those positions of of your tuple.

     (Text, Maybe Int, Int)

If `query` encounters a `NULL` in a row where the corresponding Haskell type is not `Maybe`, it will throw a `ResultError` exception.

## Type conversions

Conversion of SQL values to Haskell values is somewhat permissive. Here are the rules.

- For numeric types, any Haskell type that can accurately represent all values of the given PostgreSQL type is considered "compatible". For instance, you can always extract a PostgreSQL 16-bit `SMALLINT` column to a Haskell `Int`. The Haskell `Float` type can accurately represent a `SMALLINT`, so it is considered compatble with those types.
- A numeric compatibility check is based only on the type of a column, not on its values. For instance, a PostgreSQL 64-bit `BIGINT` column will be considered incompatible with a Haskell `Int16`, even if it contains the value `1`.
- If a numeric incompatibility is found, `query` will throw a `ResultError`.
- The `String` and `Text` types are assumed to be encoded as UTF-8. If you use some other encoding, decoding may fail or give wrong results. In such cases, write a `newtype` wrapper and a custom `Result` instance to handle your encoding.

# Types

data ConnectInfo

Constructors

ConnectInfo |

Fields

connectHost :: String
connectPort :: Word16
connectUser :: String
connectPassword :: String
connectDatabase :: String

Instances

Eq ConnectInfo |
Read ConnectInfo |
Show ConnectInfo |
Typeable ConnectInfo |

data Connection

data Query

A query string. This type is intended to make it difficult to construct a SQL query by concatenating string fragments, as that is an extremely common way to accidentally introduce SQL injection vulnerabilities into an application.

This type is an instance of `IsString`, so the easiest way to construct a query is to enable the `OverloadedStrings` language extension and then simply write the query in double quotes.

     {-# LANGUAGE OverloadedStrings #-}

     import Database.PostgreSQL.Simple

     q :: Query
     q = "select ?"

The underlying type is a `ByteString`, and literal Haskell strings that contain Unicode characters will be correctly transformed to UTF-8.

Instances

Eq Query |
Ord Query |
Read Query |
Show Query |
Typeable Query |
IsString Query |
Monoid Query |

class ToRow a

A collection type that can be turned into a list of rendering `Action`s.

Instances should use the `render` method of the `Param` class to perform conversion of each element of the collection.

Instances

ToRow () |
ToField a => ToRow [a] |
ToField a => ToRow (Only a) |
(ToField a, ToField b) => ToRow (a, b) |
(ToRow a, ToRow b) => ToRow (:. a b) |
(ToField a, ToField b, ToField c) => ToRow (a, b, c) |
(ToField a, ToField b, ToField c, ToField d) => ToRow (a, b, c, d) |
(ToField a, ToField b, ToField c, ToField d, ToField e) => ToRow (a, b, c, d, e) |
(ToField a, ToField b, ToField c, ToField d, ToField e, ToField f) => ToRow (a, b, c, d, e, f) |
(ToField a, ToField b, ToField c, ToField d, ToField e, ToField f, ToField g) => ToRow (a, b, c, d, e, f, g) |
(ToField a, ToField b, ToField c, ToField d, ToField e, ToField f, ToField g, ToField h) => ToRow (a, b, c, d, e, f, g, h) |
(ToField a, ToField b, ToField c, ToField d, ToField e, ToField f, ToField g, ToField h, ToField i) => ToRow (a, b, c, d, e, f, g, h, i) |
(ToField a, ToField b, ToField c, ToField d, ToField e, ToField f, ToField g, ToField h, ToField i, ToField j) => ToRow (a, b, c, d, e, f, g, h, i, j) |

class FromRow a

A collection type that can be converted from a sequence of fields. Instances are provided for tuples up to 10 elements and lists of any length.

Note that instances can defined outside of postgresql-simple, which is often useful. For example, here's an instance for a user-defined pair:

    data User = User { name :: String, fileQuota :: Int }

    instance FromRow User where
         fromRow = User <$> field <*> field

The number of calls to `field` must match the number of fields returned in a single row of the query result. Otherwise, a `ConversionFailed` exception will be thrown.

Note that `field` evaluates it's result to WHNF, so the caveats listed in previous versions of postgresql-simple no longer apply. Instead, look at the caveats associated with user-defined implementations of `fromRow`.

Instances

FromField a => FromRow [a] |
FromField a => FromRow (Only a) |
(FromField a, FromField b) => FromRow (a, b) |
(FromRow a, FromRow b) => FromRow (:. a b) |
(FromField a, FromField b, FromField c) => FromRow (a, b, c) |
(FromField a, FromField b, FromField c, FromField d) => FromRow (a, b, c, d) |
(FromField a, FromField b, FromField c, FromField d, FromField e) => FromRow (a, b, c, d, e) |
(FromField a, FromField b, FromField c, FromField d, FromField e, FromField f) => FromRow (a, b, c, d, e, f) |
(FromField a, FromField b, FromField c, FromField d, FromField e, FromField f, FromField g) => FromRow (a, b, c, d, e, f, g) |
(FromField a, FromField b, FromField c, FromField d, FromField e, FromField f, FromField g, FromField h) => FromRow (a, b, c, d, e, f, g, h) |
(FromField a, FromField b, FromField c, FromField d, FromField e, FromField f, FromField g, FromField h, FromField i) => FromRow (a, b, c, d, e, f, g, h, i) |
(FromField a, FromField b, FromField c, FromField d, FromField e, FromField f, FromField g, FromField h, FromField i, FromField j) => FromRow (a, b, c, d, e, f, g, h, i, j) |

newtype In a

Wrap a list of values for use in an `IN` clause. Replaces a single "`?`" character with a parenthesized list of rendered values.

Example:

     query c "select * from whatever where id in ?" (Only (In [3,4,5]))

Constructors

In a |

Instances

Functor In |
Typeable1 In |
Eq a => Eq (In a) |
Ord a => Ord (In a) |
Read a => Read (In a) |
Show a => Show (In a) |
ToField a => ToField (In [a]) |

newtype Binary a

Wrap binary data for use as a `bytea` value.

Constructors

Binary a |

Instances

Functor Binary |
Typeable1 Binary |
Eq a => Eq (Binary a) |
Ord a => Ord (Binary a) |
Read a => Read (Binary a) |
Show a => Show (Binary a) |
ToField (Binary ByteString) |
ToField (Binary ByteString) |
FromField (Binary ByteString) |
FromField (Binary ByteString) |

newtype Only a

A single-value "collection".

This is useful if you need to supply a single parameter to a SQL query, or extract a single column from a SQL result.

Parameter example:

    query c "select x from scores where x > ?" (Only (42::Int))

Result example:

    xs <- query_ c "select id from users"
    forM_ xs $ \(Only id) -> {- ... -}

Constructors

Only |

Fields

fromOnly :: a

Instances

Functor Only |
Typeable1 Only |
Eq a => Eq (Only a) |
Ord a => Ord (Only a) |
Read a => Read (Only a) |
Show a => Show (Only a) |
ToField a => ToRow (Only a) |
FromField a => FromRow (Only a) |

data h :. t

A composite type to parse your custom data structures without having to define dummy newtype wrappers every time.

     instance FromRow MyData where ...

     instance FromRow MyData2 where ...

then I can do the following for free:

     res <- query' c ...
     forM res $ \(MyData{..} :. MyData2{..}) -> do
       ....

Constructors

h :. t |

Instances

Typeable2 :. |
(Eq h, Eq t) => Eq (:. h t) |
(Ord h, Ord t) => Ord (:. h t) |
(Read h, Read t) => Read (:. h t) |
(Show h, Show t) => Show (:. h t) |
(ToRow a, ToRow b) => ToRow (:. a b) |
(FromRow a, FromRow b) => FromRow (:. a b) |

## Exceptions

data SqlError

Constructors

SqlError |

Fields

sqlState :: ByteString
sqlNativeError :: Int
sqlErrorMsg :: ByteString

Instances

Show SqlError |
Typeable SqlError |
Exception SqlError |

data FormatError

Exception thrown if a `Query` could not be formatted correctly. This may occur if the number of '`?`' characters in the query string does not match the number of parameters provided.

Instances

Eq FormatError |
Show FormatError |
Typeable FormatError |
Exception FormatError |

data QueryError

Exception thrown if `query` is used to perform an `INSERT`-like operation, or `execute` is used to perform a `SELECT`-like operation.

Instances

Eq QueryError |
Show QueryError |
Typeable QueryError |
Exception QueryError |

data ResultError

Exception thrown if conversion from a SQL value to a Haskell value fails.

Instances

Eq ResultError |
Show ResultError |
Typeable ResultError |
Exception ResultError |

# Connection management

connect :: ConnectInfo -> IO Connection

Connect with the given username to the given database. Will throw an exception if it cannot connect.

connectPostgreSQL :: ByteString -> IO Connection

Attempt to make a connection based on a libpq connection string. See http://www.postgresql.org/docs/9.1/static/libpq-connect.html for more information.

postgreSQLConnectionString :: ConnectInfo -> ByteString

Turns a `ConnectInfo` data structure into a libpq connection string.

defaultConnectInfo :: ConnectInfo

Default information for setting up a connection.

Defaults are as follows:

- Server on `localhost`
- Port on `5432`
- User `postgres`
- No password
- Database `postgres`

Use as in the following example:

     connect defaultConnectInfo { connectHost = "db.example.com" }

close :: Connection -> IO ()

# Queries that return results

query :: (ToRow q, FromRow r) => Connection -> Query -> q -> IO [r]

Perform a `SELECT` or other SQL query that is expected to return results. All results are retrieved and converted before this function returns.

When processing large results, this function will consume a lot of client-side memory. Consider using `fold` instead.

Exceptions that may be thrown:

- `FormatError`: the query string could not be formatted correctly.
- `QueryError`: the result contains no columns (i.e. you should be using `execute` instead of `query`).
- `ResultError`: result conversion failed.

query_ :: FromRow r => Connection -> Query -> IO [r]

A version of `query` that does not perform query substitution.

# Queries that stream results

data FoldOptions

Constructors

FoldOptions |

Fields

fetchQuantity :: !FetchQuantity
transactionMode :: !TransactionMode

data FetchQuantity

Constructors

Automatic |
Fixed !Int |

defaultFoldOptions :: FoldOptions

fold :: (FromRow row, ToRow params) => Connection -> Query -> params -> a -> (a -> row -> IO a) -> IO a

Perform a `SELECT` or other SQL query that is expected to return results. Results are streamed incrementally from the server, and consumed via a left fold.

When dealing with small results, it may be simpler (and perhaps faster) to use `query` instead.

This fold is not strict. The stream consumer is responsible for forcing the evaluation of its result to avoid space leaks.

Exceptions that may be thrown:

- `FormatError`: the query string could not be formatted correctly.
- `QueryError`: the result contains no columns (i.e. you should be using `execute` instead of `query`).
- `ResultError`: result conversion failed.

foldWithOptions :: (FromRow row, ToRow params) => FoldOptions -> Connection -> Query -> params -> a -> (a -> row -> IO a) -> IO a

fold_

Arguments

:: FromRow r |
=> Connection |
-> Query | Query.
-> a | Initial state for result consumer.
-> (a -> r -> IO a) | Result consumer.
-> IO a |

A version of `fold` that does not perform query substitution.

foldWithOptions_

Arguments

:: FromRow r |
=> FoldOptions |
-> Connection |
-> Query | Query.
-> a | Initial state for result consumer.
-> (a -> r -> IO a) | Result consumer.
-> IO a |

forEach

Arguments

:: (ToRow q, FromRow r) |
=> Connection |
-> Query | Query template.
-> q | Query parameters.
-> (r -> IO ()) | Result consumer.
-> IO () |

A version of `fold` that does not transform a state value.

forEach_

Arguments

:: FromRow r |
=> Connection |
-> Query | Query template.
-> (r -> IO ()) | Result consumer.
-> IO () |

A version of `forEach` that does not perform query substitution.

returning :: (ToRow q, FromRow r) => Connection -> Query -> [q] -> IO [r]

Execute `INSERT ... RETURNING`, `UPDATE ... RETURNING`, or other SQL query that accepts multi-row input and is expected to return results. Note that it is possible to write ``query` conn INSERT ... RETURNING ... ...` in cases where you are only inserting a single row, and do not need functionality analogous to `executeMany`.

Throws `FormatError` if the query could not be formatted correctly.

# Statements that do not return results

execute :: ToRow q => Connection -> Query -> q -> IO Int64

Execute an `INSERT`, `UPDATE`, or other SQL query that is not expected to return results.

Returns the number of rows affected.

Throws `FormatError` if the query could not be formatted correctly.

execute_ :: Connection -> Query -> IO Int64

A version of `execute` that does not perform query substitution.

executeMany :: ToRow q => Connection -> Query -> [q] -> IO Int64

Execute a multi-row `INSERT`, `UPDATE`, or other SQL query that is not expected to return results.

Returns the number of rows affected.

Throws `FormatError` if the query could not be formatted correctly.

# Transaction handling

withTransaction :: Connection -> IO a -> IO a

Execute an action inside a SQL transaction.

This function initiates a transaction with a "`begin transaction`" statement, then executes the supplied action. If the action succeeds, the transaction will be completed with `commit` before this function returns.

If the action throws any kind of exception (not just a PostgreSQL-related exception), the transaction will be rolled back using `rollback`, then the exception will be rethrown.

withTransactionSerializable :: Connection -> IO a -> IO a

Execute an action inside of a `Serializable` transaction. If a serialization failure occurs, roll back the transaction and try again. Be warned that this may execute the IO action multiple times.

A `Serializable` transaction creates the illusion that your program has exclusive access to the database. This means that, even in a concurrent setting, you can perform queries in sequence without having to worry about what might happen between one statement and the next.

Think of it as STM, but without `retry`.

data TransactionMode

Constructors

TransactionMode |

Fields

isolationLevel :: !IsolationLevel
readWriteMode :: !ReadWriteMode

Instances

Eq TransactionMode |
Show TransactionMode |

data IsolationLevel

Of the four isolation levels defined by the SQL standard, these are the three levels distinguished by PostgreSQL as of version 9.0. See http://www.postgresql.org/docs/9.1/static/transaction-iso.html for more information. Note that prior to PostgreSQL 9.0, `RepeatableRead` was equivalent to `Serializable`.

Constructors

DefaultIsolationLevel | the isolation level will be taken from PostgreSQL's per-connection `default_transaction_isolation` variable, which is initialized according to the server's config. The default configuration is `ReadCommitted`.
ReadCommitted |
RepeatableRead |
Serializable |

Instances

Bounded IsolationLevel |
Enum IsolationLevel |
Eq IsolationLevel |
Ord IsolationLevel |
Show IsolationLevel |

data ReadWriteMode

Constructors

DefaultReadWriteMode | the read-write mode will be taken from PostgreSQL's per-connection `default_transaction_read_only` variable, which is initialized according to the server's config. The default configuration is `ReadWrite`.
ReadWrite |
ReadOnly |

Instances

Bounded ReadWriteMode |
Enum ReadWriteMode |
Eq ReadWriteMode |
Ord ReadWriteMode |
Show ReadWriteMode |

defaultTransactionMode :: TransactionMode

defaultIsolationLevel :: IsolationLevel

defaultReadWriteMode :: ReadWriteMode

withTransactionLevel :: IsolationLevel -> Connection -> IO a -> IO a

Execute an action inside a SQL transaction with a given isolation level.

withTransactionMode :: TransactionMode -> Connection -> IO a -> IO a

Execute an action inside a SQL transaction with a given transaction mode.

withTransactionModeRetry :: TransactionMode -> Connection -> IO a -> IO a

Like `withTransactionMode`, but if a `SqlError` arises whose `sqlState` is `"40001"` (`serialization_failure`), this will issue a `ROLLBACK`, then try the action again. If any other exception arises, this will issue a `ROLLBACK`, but will propagate the exception instead of retrying.

This is used to implement `withTransactionSerializable`.

begin :: Connection -> IO ()

Begin a transaction.

beginLevel :: IsolationLevel -> Connection -> IO ()

Begin a transaction with a given isolation level

beginMode :: TransactionMode -> Connection -> IO ()

Begin a transaction with a given transaction mode

commit :: Connection -> IO ()

Commit a transaction.

rollback :: Connection -> IO ()

Rollback a transaction.

# Helper functions

formatMany :: ToRow q => Connection -> Query -> [q] -> IO ByteString

Format a query string with a variable number of rows.

This function is exposed to help with debugging and logging. Do not use it to prepare queries for execution.

The query string must contain exactly one substitution group, identified by the SQL keyword "`VALUES`" (case insensitive) followed by an "`(`" character, a series of one or more "`?`" characters separated by commas, and a "`)`" character. White space in a substitution group is permitted.

Throws `FormatError` if the query string could not be formatted correctly.

formatQuery :: ToRow q => Connection -> Query -> q -> IO ByteString

Format a query string.

This function is exposed to help with debugging and logging. Do not use it to prepare queries for execution.

String parameters are escaped according to the character set in use on the `Connection`.

Throws `FormatError` if the query string could not be formatted correctly.