summaryrefslogtreecommitdiff
path: root/odb/mssql/error.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-11-17 16:46:11 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-11-17 16:46:11 +0200
commite2f3b445828604945aa8ca8bfc2bf77ae7be8b81 (patch)
treee4854c3a6dd2ce5960f619e80e86c6dc8a4b4b64 /odb/mssql/error.cxx
parentbcbbad2716b09c0c70366825f5bdf2055c8d21b8 (diff)
Translate certain SQLSTATE codes to special exceptions
Diffstat (limited to 'odb/mssql/error.cxx')
-rw-r--r--odb/mssql/error.cxx127
1 files changed, 111 insertions, 16 deletions
diff --git a/odb/mssql/error.cxx b/odb/mssql/error.cxx
index 4e79a4d..b405db7 100644
--- a/odb/mssql/error.cxx
+++ b/odb/mssql/error.cxx
@@ -3,6 +3,8 @@
// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
// license : GNU GPL v2; see accompanying LICENSE file
+#include <string>
+
#include <odb/mssql/mssql.hxx>
#include <odb/mssql/error.hxx>
#include <odb/mssql/connection.hxx>
@@ -24,6 +26,101 @@ namespace odb
char msg[512]; // Will be truncated if doesn't fit.
SQLSMALLINT msg_size;
+ // We need to translate certain sqlstate codes to special exceptions,
+ // such as deadlock, timeout, etc. The problem is we can have multiple
+ // records potentially with different sqlstate codes. If we have both,
+ // say, a deadlock code and some other code, then we should probably
+ // throw database_exception, which is more severe. To implement this
+ // we are going to pre-scan the records looking for the codes we are
+ // interested in. If in the process we see any other code, then we
+ // stop and go ahead to prepare and throw database_exception.
+ //
+ enum code
+ {
+ code_none,
+ code_deadlock,
+ code_timeout,
+ code_connection_lost,
+ };
+
+ code c (code_none);
+
+ for (SQLSMALLINT i (1);; ++i)
+ {
+ r = SQLGetDiagRec (htype,
+ h,
+ i,
+ (SQLCHAR*) sqlstate,
+ &native_code,
+ 0,
+ 0,
+ &msg_size);
+
+ string s (sqlstate);
+
+ if (r == SQL_NO_DATA)
+ break;
+ else if (SQL_SUCCEEDED (r))
+ {
+ code nc;
+
+ if (s == "40001") // Serialization failure (native code 1205).
+ nc = code_deadlock;
+ else if (s == "HYT00") // Timeout expired.
+ nc = code_timeout;
+ else if (s == "HYT01") // Connection timeout expired.
+ {
+ nc = code_timeout;
+
+ if (conn != 0)
+ conn->mark_failed ();
+ }
+ else if (s == "08S01") // Link failure.
+ {
+ nc = code_connection_lost;
+
+ if (conn != 0)
+ conn->mark_failed ();
+ }
+ else if (s == "01000") // General warning.
+ continue;
+ else
+ {
+ c = code_none;
+ break;
+ }
+
+ if (c != code_none && c != nc)
+ {
+ // Several different codes.
+ //
+ c = code_none;
+ break;
+ }
+
+ c = nc;
+ }
+ else
+ {
+ c = code_none;
+ break;
+ }
+ }
+
+ switch (c)
+ {
+ case code_deadlock:
+ throw deadlock ();
+ case code_timeout:
+ throw timeout ();
+ case code_connection_lost:
+ throw connection_lost ();
+ case code_none:
+ break;
+ }
+
+ // Some other error code. Prepare database_exception.
+ //
database_exception e;
for (SQLSMALLINT i (1);; ++i)
@@ -41,7 +138,14 @@ namespace odb
break;
else if (SQL_SUCCEEDED (r))
{
- //@@ TODO: translate deadlock, timeout, connection_lost exceptions
+ if (conn != 0)
+ {
+ string s (sqlstate);
+
+ if (s == "08S01" || // Link failure.
+ s == "HYT01") // Connection timeout.
+ conn->mark_failed ();
+ }
e.append (native_code, sqlstate, msg);
}
@@ -53,21 +157,6 @@ namespace odb
if (e.size () == 0)
e.append (0, "?????", "no diagnostic record (using wrong handle?)");
- // Check if the connection has gone bad and mark it as failed if so.
- //
- if (conn != 0)
- {
- SQLUINTEGER dead (0);
- r = SQLGetConnectAttr (conn->handle (),
- SQL_ATTR_CONNECTION_DEAD,
- (SQLPOINTER) &dead,
- SQL_IS_UINTEGER,
- 0);
-
- if (!SQL_SUCCEEDED (r) || dead == SQL_CD_TRUE)
- conn->mark_failed ();
- }
-
throw e;
}
@@ -78,6 +167,12 @@ namespace odb
}
void
+ translate_error (connection& c, const auto_handle<SQL_HANDLE_STMT>& h)
+ {
+ translate_error (h, SQL_HANDLE_STMT, &c);
+ }
+
+ void
translate_error (SQLHANDLE h, SQLSMALLINT htype)
{
translate_error (h, htype, 0);