hdbi-1.3.0: Haskell Database Independent interface

MaintainerAleksey Uymanov <s9gf4ult@gmail.com>
Safe HaskellNone







class ToSql a whereSource

All types must convert to SqlValue safely and unambiguously. That's why there is no ''safeToSql'' method


toSql :: a -> SqlValueSource

class FromSql a whereSource


safeFromSql :: SqlValue -> Either ConvertError aSource

fromSql :: SqlValue -> aSource

Unsafe method, throws ConvertError if convertion failed. Has default implementation.

class ToRow a whereSource


toRow :: a -> [SqlValue]Source


ToRow ()

instance for conveniently pass empty list of parameters

ToRow SqlValue 
ToRow [SqlValue] 
ToSql a => ToRow (Maybe a)

This instance must not be considered as (Maybe row) but as row with exactly one nullable value

(ToSql a, ToSql b) => ToRow (Either a b) 
(ToSql a, ToSql b) => ToRow (a, b) 
(ToSql a, ToSql b, ToSql c) => ToRow (a, b, c) 
(ToSql a, ToSql b, ToSql c, ToSql d) => ToRow (a, b, c, d) 
(ToSql a, ToSql b, ToSql c, ToSql d, ToSql e) => ToRow (a, b, c, d, e) 
(ToSql a, ToSql b, ToSql c, ToSql d, ToSql e, ToSql f) => ToRow (a, b, c, d, e, f) 
(ToSql a, ToSql b, ToSql c, ToSql d, ToSql e, ToSql f, ToSql g) => ToRow (a, b, c, d, e, f, g) 

class FromRow a whereSource


FromRow ()

instance for convenient ignoring all the parameters

FromRow SqlValue 
FromRow [SqlValue] 
FromSql a => FromRow (Maybe a)

This instance must not be considered as (Maybe row) but as row with exactly one nullable value

(FromSql a, FromSql b) => FromRow (Either a b) 
(FromSql a, FromSql b) => FromRow (a, b) 
(FromSql a, FromSql b, FromSql c) => FromRow (a, b, c) 
(FromSql a, FromSql b, FromSql c, FromSql d) => FromRow (a, b, c, d) 
(FromSql a, FromSql b, FromSql c, FromSql d, FromSql e) => FromRow (a, b, c, d, e) 
(FromSql a, FromSql b, FromSql c, FromSql d, FromSql e, FromSql f) => FromRow (a, b, c, d, e, f) 
(FromSql a, FromSql b, FromSql c, FromSql d, FromSql e, FromSql f, FromSql g) => FromRow (a, b, c, d, e, f, g) 

data ConvertError Source

Convertion error description. Used in FromSql typeclass.




ceReason :: String

Detailed description of convertion error


Type names must unique. Expecting names are generated by (show . typeOf) function


ceFromType :: String

name of type trying to convert from.

ceToType :: String

name of target type.

newtype BitField Source

Auxiliary type to represent bit field outside of SqlValue




unBitField :: Word64

SQL value marshalling

data SqlValue Source

SqlValue is the main type for expressing Haskell values to SQL databases.


SqlValue is an intermediate type to storerecevie data tofrom the database. Every database driver will do it's best to properly convert any SqlValue to the database record's field, and properly convert the record's field to SqlValue back.

The SqlValue has predefined FromSql and ToSql instances for many Haskell's types. Any Haskell's type can be converted to the SqlValue with toSql function. There is no safeToSql function because toSql never fails. Also, any SqlValue type can be converted to almost any Haskell's type as well. Not any SqlValue can be converted back to Haskell's type, so there is safeFromSql function to do that safely. There is also unsafe toSql function of caurse.

You can sure, that fromSql . toSql == id


SqlValue constructors is the MINIMAL set of constructors, required to represent the most wide range of native database types.

For example, there is FLOAT native database type and DOUBLE, but any DOUBLE can carry any FLOAT value, so there is no need to create SqlValue constructor to represent FLOAT type, we can do it with Double. But there is DECIMAL database type, representing arbitrary precision value which can be carried just by Decimal Haskell's type, so we need a constructor for it.

There is no SqlRational any more, because there is no one database which have native Rational type. This is the key idea: if database can not store this type natively we will not create SqlValue clause for it.

Each SqlValue constructor is documented or self-explaining to understand what it is needed for.

'ToSql' and 'FromSql' INSTANCES

The key idea is to do the most obvious conversion between types only if it is not ambiguous. For example, the most obvious conversion of Double to Int32 is just truncate the Double, the most obvious conversion of String to UTCTime is to try read the String as date and time. But there is no obvious way to convert Int32 to UTCTime, so if you will try to convert (SqlInteger 44) to date you will fail. User must handle this cases properly converting values with right way. It is not very good idea to silently perform strange and ambiguous convertions between absolutely different data types.


There may be sometimes an error during conversion. For instance, if you have an SqlText and attempting to convert it to an Integer, but it doesn't parse as an Integer, you will get an error. This will be indicated as an exception using fromSql, or a Left result using safeFromSql.


Any SqlValue can be converted to Text and then readed from Text back. This is guaranteed by tests, so the database driver's author can use it to store and read data through Text for types which is not supported by the database natively.


We are using lazy Text everywhere because it is faster than String and has builders. Strict text can be converted to one-chanked lazy text with O(1) complexity, but lazy to strict converts with O(n) complexity, so it is logical to use lazy Text.

We are not using ByteString as text encoded in UTF-8, ByteStrings are just sequences of bytes. We are using strict ByteStrings because HDBI drivers uses them to pass the ByteString to the C library as CString, so it must be strict.

We are not using String as data of query or as query itself because it is not effective in memory and cpu.


We are not using time with timezone, because there is no one database working with it natively except PostgreSQL, but the documentations of PostgreSQL says

To address these difficulties, we recommend using datetime types that contain both date and time when using time zones. We do not recommend using the type time with time zone (though it is supported by PostgreSQL for legacy applications and for compliance with the SQL standard). PostgreSQL assumes your local time zone for any type containing only date or time./

This is not recomended to use time with timezone.

We are using UTCTime instead of TimeWithTimezone because no one database actually save timezone information. All databases just convert datetime to UTCTime when save data and convert UTCTime back to LOCAL SERVER TIMEZONE when returning the data. So it is logical to work with timezones on the haskell side.

Time intervals are not widely supported, actually just in PostgreSQL and Oracle. So, if you need them you can serialize throgh SqlText by hands, or write your own ToSql and FromSql instances to do that more convenient.


Two SqlValues are considered to be equal if one of these hold. The first comparison that can be made is controlling; if none of these comparisons can be made, then they are not equal:

  • Both are NULL
  • Both represent the same type and the encapsulated values are considered equal by applying (==) to them
  • The values of each, when converted to a String, are equal.


SqlDecimal Decimal

Arbitrary precision DECIMAL value

SqlInteger Integer

Any Integer, including Int32, Int64 and Words.

SqlDouble Double 
SqlText Text 
SqlBlob ByteString

Blob field in the database. This field can not be implicitly converted to any other type because it is just an array of bytes, not an UTF-8 encoded string.

SqlBool Bool 
SqlBitField BitField

Represent bit field with 64 bits


UUID value http:en.wikipedia.orgwikiUUID

SqlUTCTime UTCTime


SqlLocalDate Day

Local YYYY-MM-DD (no timezone)

SqlLocalTimeOfDay TimeOfDay

Local HH:MM:SS (no timezone)

SqlLocalTime LocalTime

Local YYYY-MM-DD HH:MM:SS (no timezone)


NULL in SQL or Nothing in Haskell

Auxiliary convertion functions

one :: ToSql a => a -> [SqlValue]Source

creates row of one element

onei :: Integer -> [SqlValue]Source

create row of one Integer element

oned :: Double -> [SqlValue]Source

create row of one Double element

onet :: Text -> [SqlValue]Source

onetl :: Text -> [SqlValue]Source

safeUnOne :: FromSql a => [SqlValue] -> Either ConvertError aSource

unwrap the row of one element safely

unone :: FromSql a => [SqlValue] -> aSource

same as safeUnOne but throws an exception if not converted

unonei :: [SqlValue] -> IntegerSource

unwrap row of one Integer

unonet :: [SqlValue] -> TextSource

unonetl :: [SqlValue] -> TextSource