@@ -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(..))
@@ -95,10 +96,15 @@ data SqlType
9596
9697data SqlError = SqlError {
9798 sqlState :: ByteString
98− , sqlNativeError :: Int
99+ , sqlExecStatus :: ExecStatus
99100 , sqlErrorMsg :: ByteString
101+ , sqlErrorDetail :: ByteString
102+ , sqlErrorHint :: ByteString
100103 } deriving (Show, Typeable)
101104
105+fatalError :: ByteString -> SqlError
106+fatalError msg = SqlError "" FatalError msg "" ""
107+
102108instance Exception SqlError
103109
104110-- | Exception thrown if 'query' is used to perform an @INSERT@-like
@@ -172,9 +178,7 @@ connectPostgreSQL connstr = do
172178 return wconn
173179 _ -> do
174180 msg <- maybe "connectPostgreSQL error" id <$> PQ.errorMessage conn
175− throwIO $ SqlError { sqlNativeError = -1 -- FIXME?
176− , sqlErrorMsg = msg
177− , sqlState = "" }
181+ throwIO $ fatalError msg
178182
179183-- | Turns a 'ConnectInfo' data structure into a libpq connection string.
180184
@@ -223,9 +227,7 @@ exec conn sql =
223227 case mres of
224228 Nothing -> do
225229 msg <- maybe "execute error" id <$> PQ.errorMessage h
226− throwIO $ SqlError { sqlNativeError = -1 -- FIXME?
227− , sqlErrorMsg = msg
228− , sqlState = "" }
230+ throwIO $ fatalError msg
229231 Just res -> do
230232 return res
231233
@@ -270,21 +272,22 @@ finishExecute _conn q result = do
270272 else error ("finishExecute: not an int: " ++ B8.unpack str)
271273
272274throwResultError :: ByteString -> PQ.Result -> PQ.ExecStatus -> IO a
273−throwResultError context result status = do
274− errormsg <- maybe "" id <$> PQ.resultErrorMessage result
275− statusmsg <- PQ.resStatus status
275+throwResultError _ result status = do
276+ errormsg <- fromMaybe "" <$>
277+ PQ.resultErrorField result PQ.DiagMessagePrimary
278+ detail <- fromMaybe "" <$>
279+ PQ.resultErrorField result PQ.DiagMessageDetail
280+ hint <- fromMaybe "" <$>
281+ PQ.resultErrorField result PQ.DiagMessageHint
276282 state <- maybe "" id <$> PQ.resultErrorField result PQ.DiagSqlstate
277283 throwIO $ SqlError { sqlState = state
278− , sqlNativeError = fromEnum status
279− , sqlErrorMsg = B.concat [ context, ": ", statusmsg
280− , ": ", errormsg ]}
284+ , sqlExecStatus = status
285+ , sqlErrorMsg = errormsg
286+ , sqlErrorDetail = detail
287+ , sqlErrorHint = hint }
281288
282289disconnectedError :: SqlError
283−disconnectedError = SqlError {
284− sqlNativeError = -1,
285− sqlErrorMsg = "connection disconnected",
286− sqlState = ""
287− }
290+disconnectedError = fatalError "connection disconnected"
288291
289292-- | Atomically perform an action with the database handle, if there is one.
290293withConnection :: Connection -> (PQ.Connection -> IO a) -> IO a