@@ -25,16 +25,17 @@ import Control.Applicative
2525import Control.Exception
2626import Control.Concurrent.MVar
2727import Data.ByteString(ByteString)
28−import qualified Data.ByteString as B
2928import qualified Data.ByteString.Char8 as B8
3029import Data.Char (ord)
3130import Data.Int (Int64)
3231import qualified Data.IntMap as IntMap
32+import Data.Maybe(fromMaybe)
3333import Data.String
3434import Data.Typeable
3535import Data.Word
3636import Database.PostgreSQL.LibPQ(Oid(..))
3737import qualified Database.PostgreSQL.LibPQ as PQ
38+import Database.PostgreSQL.LibPQ(ExecStatus(..))
3839import Database.PostgreSQL.Simple.BuiltinTypes (BuiltinType)
3940import Database.PostgreSQL.Simple.Ok
4041import Database.PostgreSQL.Simple.Types (Query(..))
@@ -85,10 +86,15 @@ data SqlType
8586
8687data SqlError = SqlError {
8788 sqlState :: ByteString
88− , sqlNativeError :: Int
89+ , sqlExecStatus :: ExecStatus
8990 , sqlErrorMsg :: ByteString
91+ , sqlErrorDetail :: ByteString
92+ , sqlErrorHint :: ByteString
9093 } deriving (Show, Typeable)
9194
95+fatalError :: ByteString -> SqlError
96+fatalError msg = SqlError "" FatalError msg "" ""
97+
9298instance Exception SqlError
9399
94100-- | Exception thrown if 'query' is used to perform an @INSERT@-like
@@ -162,9 +168,7 @@ connectPostgreSQL connstr = do
162168 return wconn
163169 _ -> do
164170 msg <- maybe "connectPostgreSQL error" id <$> PQ.errorMessage conn
165− throwIO $ SqlError { sqlNativeError = -1 -- FIXME?
166− , sqlErrorMsg = msg
167− , sqlState = "" }
171+ throwIO $ fatalError msg
168172
169173-- | Turns a 'ConnectInfo' data structure into a libpq connection string.
170174
@@ -213,9 +217,7 @@ exec conn sql =
213217 case mres of
214218 Nothing -> do
215219 msg <- maybe "execute error" id <$> PQ.errorMessage h
216− throwIO $ SqlError { sqlNativeError = -1 -- FIXME?
217− , sqlErrorMsg = msg
218− , sqlState = "" }
220+ throwIO $ fatalError msg
219221 Just res -> do
220222 return res
221223
@@ -260,21 +262,22 @@ finishExecute _conn q result = do
260262 else error ("finishExecute: not an int: " ++ B8.unpack str)
261263
262264throwResultError :: ByteString -> PQ.Result -> PQ.ExecStatus -> IO a
263−throwResultError context result status = do
264− errormsg <- maybe "" id <$> PQ.resultErrorMessage result
265− statusmsg <- PQ.resStatus status
265+throwResultError _ result status = do
266+ errormsg <- fromMaybe "" <$>
267+ PQ.resultErrorField result PQ.DiagMessagePrimary
268+ detail <- fromMaybe "" <$>
269+ PQ.resultErrorField result PQ.DiagMessageDetail
270+ hint <- fromMaybe "" <$>
271+ PQ.resultErrorField result PQ.DiagMessageHint
266272 state <- maybe "" id <$> PQ.resultErrorField result PQ.DiagSqlstate
267273 throwIO $ SqlError { sqlState = state
268− , sqlNativeError = fromEnum status
269− , sqlErrorMsg = B.concat [ context, ": ", statusmsg
270− , ": ", errormsg ]}
274+ , sqlExecStatus = status
275+ , sqlErrorMsg = errormsg
276+ , sqlErrorDetail = detail
277+ , sqlErrorHint = hint }
271278
272279disconnectedError :: SqlError
273−disconnectedError = SqlError {
274− sqlNativeError = -1,
275− sqlErrorMsg = "connection disconnected",
276− sqlState = ""
277− }
280+disconnectedError = fatalError "connection disconnected"
278281
279282-- | Atomically perform an action with the database handle, if there is one.
280283withConnection :: Connection -> (PQ.Connection -> IO a) -> IO a