@@ -25,16 +25,17 @@ import Control.Applicative
25import Control.Exception
25import Control.Exception
26import Control.Concurrent.MVar
26import Control.Concurrent.MVar
27import Data.ByteString(ByteString)
27import Data.ByteString(ByteString)
28−import qualified Data.ByteString as B
29import qualified Data.ByteString.Char8 as B8
28import qualified Data.ByteString.Char8 as B8
30import Data.Char (ord)
29import Data.Char (ord)
31import Data.Int (Int64)
30import Data.Int (Int64)
32import qualified Data.IntMap as IntMap
31import qualified Data.IntMap as IntMap
32+import Data.Maybe(fromMaybe)
33import Data.String
33import Data.String
34import Data.Typeable
34import Data.Typeable
35import Data.Word
35import Data.Word
36import Database.PostgreSQL.LibPQ(Oid(..))
36import Database.PostgreSQL.LibPQ(Oid(..))
37import qualified Database.PostgreSQL.LibPQ as PQ
37import qualified Database.PostgreSQL.LibPQ as PQ
38+import Database.PostgreSQL.LibPQ(ExecStatus(..))
38import Database.PostgreSQL.Simple.BuiltinTypes (BuiltinType)
39import Database.PostgreSQL.Simple.BuiltinTypes (BuiltinType)
39import Database.PostgreSQL.Simple.Ok
40import Database.PostgreSQL.Simple.Ok
40import Database.PostgreSQL.Simple.Types (Query(..))
41import Database.PostgreSQL.Simple.Types (Query(..))
@@ -95,10 +96,15 @@ data SqlType
96data SqlError = SqlError {
97data SqlError = SqlError {
97 sqlState :: ByteString
98 sqlState :: ByteString
98− , sqlNativeError :: Int
99+ , sqlExecStatus :: ExecStatus
99 , sqlErrorMsg :: ByteString
100 , sqlErrorMsg :: ByteString
101+ , sqlErrorDetail :: ByteString
102+ , sqlErrorHint :: ByteString
100 } deriving (Show, Typeable)
103 } deriving (Show, Typeable)
105+fatalError :: ByteString -> SqlError
106+fatalError msg = SqlError "" FatalError msg "" ""
102instance Exception SqlError
108instance Exception SqlError
104-- | Exception thrown if 'query' is used to perform an @INSERT@-like
110-- | Exception thrown if 'query' is used to perform an @INSERT@-like
@@ -172,9 +178,7 @@ connectPostgreSQL connstr = do
172 return wconn
178 return wconn
174 msg <- maybe "connectPostgreSQL error" id <$> PQ.errorMessage conn
180 msg <- maybe "connectPostgreSQL error" id <$> PQ.errorMessage conn
175− throwIO $ SqlError { sqlNativeError = -1 -- FIXME?
181+ throwIO $ fatalError msg
179-- | Turns a 'ConnectInfo' data structure into a libpq connection string.
183-- | Turns a 'ConnectInfo' data structure into a libpq connection string.
@@ -223,9 +227,7 @@ exec conn sql =
223 case mres of
227 case mres of
224 Nothing -> do
228 Nothing -> do
225 msg <- maybe "execute error" id <$> PQ.errorMessage h
229 msg <- maybe "execute error" id <$> PQ.errorMessage h
226− throwIO $ SqlError { sqlNativeError = -1 -- FIXME?
230+ throwIO $ fatalError msg
229 Just res -> do
231 Just res -> do
230 return res
232 return res
@@ -270,21 +272,22 @@ finishExecute _conn q result = do
270 else error ("finishExecute: not an int: " ++ B8.unpack str)
272 else error ("finishExecute: not an int: " ++ B8.unpack str)
272throwResultError :: ByteString -> PQ.Result -> PQ.ExecStatus -> IO a
274throwResultError :: ByteString -> PQ.Result -> PQ.ExecStatus -> IO a
273−throwResultError context result status = do
275+throwResultError _ result status = do
274− errormsg <- maybe "" id <$> PQ.resultErrorMessage result
276+ errormsg <- fromMaybe "" <$>
275− statusmsg <- PQ.resStatus status
277+ PQ.resultErrorField result PQ.DiagMessagePrimary
278+ detail <- fromMaybe "" <$>
279+ PQ.resultErrorField result PQ.DiagMessageDetail
280+ hint <- fromMaybe "" <$>
281+ PQ.resultErrorField result PQ.DiagMessageHint
276 state <- maybe "" id <$> PQ.resultErrorField result PQ.DiagSqlstate
282 state <- maybe "" id <$> PQ.resultErrorField result PQ.DiagSqlstate
277 throwIO $ SqlError { sqlState = state
283 throwIO $ SqlError { sqlState = state
278− , sqlNativeError = fromEnum status
284+ , sqlExecStatus = status
279− , sqlErrorMsg = B.concat [ context, ": ", statusmsg
280− , ": ", errormsg ]}
285+ , sqlErrorMsg = errormsg
286+ , sqlErrorDetail = detail
287+ , sqlErrorHint = hint }
282disconnectedError :: SqlError
289disconnectedError :: SqlError
283−disconnectedError = SqlError {
284− sqlNativeError = -1,
285− sqlErrorMsg = "connection disconnected",
290+disconnectedError = fatalError "connection disconnected"
289-- | Atomically perform an action with the database handle, if there is one.
292-- | Atomically perform an action with the database handle, if there is one.
290withConnection :: Connection -> (PQ.Connection -> IO a) -> IO a
293withConnection :: Connection -> (PQ.Connection -> IO a) -> IO a