content: {-- snippet sqlerror --}
  {-# LANGUAGE DeriveDataTypeable #-}
  
  import Data.Dynamic
  import Control.Exception
  
  data SqlError = SqlError {seState :: String,
                            seNativeError :: Int,
                            seErrorMsg :: String}
                  deriving (Eq, Show, Read, Typeable)
  {-- /snippet sqlerror --}
  
  {-- snippet catch --}
  {- | Execute the given IO action.
  
  If it raises a 'SqlError', then execute the supplied 
  handler and return its return value.  Otherwise, proceed
  as normal. -}
  catchSql :: IO a -> (SqlError -> IO a) -> IO a
  catchSql = catchDyn
  
  {- | Like 'catchSql', with the order of arguments reversed. -}
  handleSql :: (SqlError -> IO a) -> IO a -> IO a
  handleSql = flip catchSql
  {-- /snippet catch -}
  
  {-- snippet handleSqlError --}
  {- | Catches 'SqlError's, and re-raises them as IO errors with fail.
  Useful if you don't care to catch SQL errors, but want to see a sane
  error message if one happens.  One would often use this as a 
  high-level wrapper around SQL calls. -}
  handleSqlError :: IO a -> IO a
  handleSqlError action =
      catchSql action handler
      where handler e = fail ("SQL error: " ++ show e)
  {-- /snippet handleSqlError --}
  
  {-- snippet throwSql --}
  throwSqlError :: String -> Int -> String -> a
  throwSqlError state nativeerror errormsg =
      throwDyn (SqlError state nativeerror errormsg)
  
  throwSqlErrorIO :: String -> Int -> String -> IO a
  throwSqlErrorIO state nativeerror errormsg =
      evaluate (throwSqlError state nativeerror errormsg)
  {-- /snippet throwSql --}
  
  