hmssql
Safe HaskellNone
LanguageHaskell2010

Hmssql.Errors

Description

Every exception hmssql throws.

After a nonfatal SqlServerError, DecodeError, EncodeError, UnexpectedResult, TransactionError and ResultAbandoned the connection is usable: the response was read to its end (or the request never sent). After ConnectionClosed, ConnectionBroken and ProtocolError it is not. A SqlServerError of severity 20 or more also breaks the connection. SevereError is either, as its documentation says. LoginError and LoginRedirected (and MarsNotSupported) come from connect, which then has no connection to return. ReentrantCallback and ConnectionReleased are thrown before anything is sent: after ReentrantCallback the connection is as it was; after ConnectionReleased the connection is too, but the handle that was used is not (release).

Synopsis

Documentation

data SqlServerError Source #

SQL Server reported an error (an ERROR token with severity above 10).

Severity 20 or more breaks the connection immediately, even before the server closes it. Lower severities leave the connection usable.

Constructors

SqlServerError 

Fields

sqlErrorNumber :: SqlServerError -> Int32 Source #

The server's error number (msgNumber): 2627 for a duplicate key, 1205 for a deadlock victim, and so on. Login failures use loginErrorNumber instead.

sqlErrorMessage :: SqlServerError -> Text Source #

The server's message text (msgText).

newtype LoginError Source #

The server rejected the login. loginErrorNumber says why: 18456 for a wrong password or an unknown login, 4060 for a database that can't be opened, and so on. isTransientLoginError picks out the refusals that mean the server may accept the same login shortly. hmssql never retries a login itself, so wait and try again if that suits you:

connectRetrying :: ConnectInfo -> IO Connection
connectRetrying ci = go (5 :: Int)
  where
    go n = try (connect ci) >>= \case
      Left e | n > 1, isTransientLoginError e -> threadDelay 2000000 >> go (n - 1)
      Left e -> throwIO e
      Right conn -> pure conn

loginErrorNumber :: LoginError -> Int32 Source #

The server's error number of a refused login (msgNumber).

isTransientLoginError :: LoginError -> Bool Source #

Whether the login was refused for the moment rather than for good: the server is shutting down (6005), or an Azure SQL database is not available yet, as during a failover or a scaling operation (40613), is busy (40501), or can't take the request for now (49918, 49919 and 49920). Trying the same login again after a pause may succeed. Every other refusal is False, including 4060, which a database that doesn't exist gets too.

data LoginRedirected Source #

A login redirect that was not followed. A server may accept a login but tell the client to log in to another server instead (a routing ENVCHANGE, MS-TDS 2.2.7.9): Azure SQL does this under its default connection policy from inside Azure, and availability group listeners do it for read-only routing. connect follows up to ten redirects in a row, as SqlClient does; this is thrown for the eleventh, naming where to, and for a redirect that came in plaintext after an encrypted login (EncryptOff, where anyone on the path could have written it). The connections are closed.

Constructors

LoginRedirected 

Fields

data MarsNotSupported Source #

connectMars was set, and the server answered that it doesn't do MARS. Thrown by connect (the connection is closed) rather than connecting without it: code written for several open responses would otherwise find each request abandoning the last (ResultAbandoned).

Constructors

MarsNotSupported 

newtype ProtocolError Source #

The byte stream from the server could not be interpreted. The connection is unusable afterwards.

Constructors

ProtocolError String 

newtype ConnectionClosed Source #

The connection is gone, for the given reason. Whatever the reason, the connection cannot be used again: later requests throw ConnectionBroken wrapping this exception (or, after close, this exception again). connect throws it too, when the server can't be reached or the connection fails during the handshake.

The pattern ConnectionClosed matches any reason, so \ConnectionClosed -> ... catches them all.

Bundled Patterns

pattern ConnectionClosed :: ConnectionClosed

Matches a ConnectionClosed with any CloseReason. As an expression, it is ConnectionClosedBy ClosedByServer.

data CloseReason Source #

Why a connection closed.

Constructors

ClosedByServer

The server closed the connection (TCP EOF, or a TLS close_notify or end of stream), as it does when the session is killed or after an error of severity 20 or more. (A killed session ends in TransportFailed instead when the server is SQL Server on Windows, which resets the connection or disconnects the pipe, and behind Azure's gateway.)

ClosedByClient

close was called, possibly from another thread while a request was in progress.

TransportFailed SomeException

Connecting, sending or receiving failed: the host name did not resolve, the TCP connect was refused, the connection was reset, a send hit a broken pipe, a TLS alert or TLS error ended the session, and so on. Carries the underlying IOException or TLSException.

Instances

Instances details
Show CloseReason Source # 
Instance details

Defined in Hmssql.Errors

newtype ConnectionBroken Source #

An earlier failure left the connection in an unknown state, so it refuses further requests. The cause is inside. The original failing operation reports its own exception (for example a fatal SqlServerError or a ProtocolError); catching ConnectionBroken alone does not catch it. unusableReason gives the same reason without a request. After an explicit close, later requests instead throw ConnectionClosedBy ClosedByClient.

Interrupting a request with an asynchronous exception (killThread, timeout, async's cancel) while it waits for or reads its response is not a failure: the statement is canceled and the connection stays usable. One that lands while the request is being sent, or while the next request drains a canceled response, breaks the connection, and is the cause here. An exception of a synchronous type thrown to a thread with throwTo can't be told from a failure inside hmssql, and breaks the connection too.

data UnusableReason Source #

Why a connection can't be used, as far as hmssql has seen. New constructors may be added. The first reason recorded stays, except that close is always reported.

Constructors

Closed CloseReason

close was called, the server closed the connection, or the transport failed.

ServerProtocolViolation String

The server sent TDS or SMP bytes that hmssql refuses (ProtocolError).

FatalServerError ServerMessage

An ERROR token of severity 20 or more.

ServerFailedConnection Done

A DONE flagged DONE_SRVERROR with no ERROR token (SevereError). The server closes the connection after it.

SendFailed SomeException

An exception left a send part-way, such as an asynchronous one or one from a parameter's source.

ReadFailed SomeException

A read failed, so the position in the byte stream is unknown.

DrainFailed SomeException

A canceled response could not be read to its end: the drain failed or was interrupted.

ResetRefused (Maybe ServerMessage)

The server refused the request that carried a reset. Nothing means a failed DONE with no message.

ResetFailed SomeException

The request that carried a reset could not be finished.

RollbackFailed SomeException

Rolling back after a failure failed or was interrupted, so the session may still hold a transaction.

ReaderThreadDied SomeException

The thread that reads from the server died. This is a bug in hmssql.

Instances

Instances details
Show UnusableReason Source # 
Instance details

Defined in Hmssql.Errors

data ResultAbandoned Source #

A result stream was consumed after a newer request was started on the same connection, which discards any unread results, or after a read of it was interrupted by an asynchronous exception, which cancels the statement (see queryS). Also thrown when pulling again from a stream that was already read to its end.

On a MARS connection (connectMars) a newer request leaves the stream open, so this is thrown only by a stream that was canceled: by cancelResponse or the end of its withQueryS, by cancelActiveStatement, a reset, the rollback of a transaction it was open in, or an interrupted read.

Constructors

ResultAbandoned 

data ReentrantCallback Source #

The connection was used from inside its own info-message callback (connectOnInfoMessage). The callback runs while a response is being read, so it cannot start another request or read a stream; collect the messages and act on them afterwards instead.

Constructors

ReentrantCallback 

data ReentrantSource Source #

A parameter or bulk source attempted a request on its own connection. The source runs while that connection's message is being sent, so a request from it could never be answered. On a MARS connection it may still read a stream that was opened earlier.

Constructors

ReentrantSource 

data ConnectionReleased Source #

The Connection handle was used after release (or after renew made a newer handle to the same connection): it went back to a pool, and another borrower may be using the connection. Requests and reads from streams it produced throw this before sending anything. Read-only inspection (connectionContext, connectionMars and inTransaction), close and renew remain available. The inspection reads cached state; it does not establish that the handle is current or that the connection is usable.

Constructors

ConnectionReleased 

data SevereError Source #

The server flagged the request as failed without saying why: a DONE token (DONE, DONEPROC or DONEINPROC) with DONE_ERROR or DONE_SRVERROR set, in a response that carried no ERROR token (an ERROR token is thrown as SqlServerError instead). SQL Server answers this way when the session is killed while the request runs: on Azure SQL Database in particular, a killed request gets one such DONE (both flags), and the gateway then resets the connection. Microsoft's clients report it as "a severe error occurred on the current command".

After a DONE_SRVERROR (severeErrorServerError) the server closes the connection, so the connection is broken at once (ServerFailedConnection); after a DONE_ERROR alone it may still be usable.

Constructors

SevereError 

Fields

severeErrorServerError :: SevereError -> Bool Source #

Whether the DONE carried DONE_SRVERROR, after which the server closes the connection.

data DecodeError Source #

A row or value from the server did not fit the requested Haskell type: a column count or SQL type the row type doesn't accept (found when the result set's columns arrive, before any row), or a value that doesn't decode (a NULL for a non-Maybe field, an out-of-range integer, a refineField that said no). The rest of the response is read before it is thrown, so the connection stays usable.

Constructors

DecodeError 

Fields

newtype EncodeError Source #

A parameter value could not be represented as a SQL Server value (or a request, such as a login with very long names, could not be encoded).

Constructors

EncodeError String 

newtype UnexpectedResult Source #

The result shape didn't match the query function used, e.g. query1 returned no rows.

Constructors

UnexpectedResult String