From e2f3b445828604945aa8ca8bfc2bf77ae7be8b81 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 17 Nov 2011 16:46:11 +0200 Subject: Translate certain SQLSTATE codes to special exceptions --- odb/mssql/database.cxx | 18 +++---- odb/mssql/database.hxx | 8 ++-- odb/mssql/error.cxx | 127 ++++++++++++++++++++++++++++++++++++++++++------- odb/mssql/error.hxx | 5 ++ 4 files changed, 128 insertions(+), 30 deletions(-) diff --git a/odb/mssql/database.cxx b/odb/mssql/database.cxx index a22ae9b..0eb0ed9 100644 --- a/odb/mssql/database.cxx +++ b/odb/mssql/database.cxx @@ -47,6 +47,11 @@ namespace odb if (!SQL_SUCCEEDED (r)) translate_error (environment_, SQL_HANDLE_ENV); } + + if (factory_.get () == 0) + factory_.reset (new connection_pool_factory ()); + + factory_->database (*this); } /* @@ -113,21 +118,16 @@ namespace odb } */ - /* database:: database (int& argc, char* argv[], bool erase, - ub2 charset, - ub2 ncharset, - OCIEnv* environment, + SQLHENV environment, auto_ptr factory) - : port_ (0), - charset_ (charset), - ncharset_ (ncharset), - environment_ (environment), + : environment_ (environment), factory_ (factory) { + /* if (environment_ == 0) { sword s (OCIEnvNlsCreate (&environment_, @@ -209,13 +209,13 @@ namespace odb oss << e; throw cli_exception (oss.str ()); } + */ if (factory_.get () == 0) factory_.reset (new connection_pool_factory ()); factory_->database (*this); } - */ void database:: print_usage (std::ostream& os) diff --git a/odb/mssql/database.hxx b/odb/mssql/database.hxx index f82d7c9..d20d860 100644 --- a/odb/mssql/database.hxx +++ b/odb/mssql/database.hxx @@ -68,17 +68,15 @@ namespace odb // argv array and the argc count is updated accordingly. This // constructor may throw the cli_exception exception. // + */ + database (int& argc, char* argv[], bool erase = false, - ub2 charset = 0, - ub2 ncharset = 0, - OCIEnv* environment = 0, + SQLHENV environment = 0, std::auto_ptr = std::auto_ptr (0)); - */ - static void print_usage (std::ostream&); 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 + #include #include #include @@ -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& h) + { + translate_error (h, SQL_HANDLE_STMT, &c); + } + + void translate_error (SQLHANDLE h, SQLSMALLINT htype) { translate_error (h, htype, 0); diff --git a/odb/mssql/error.hxx b/odb/mssql/error.hxx index 35906b7..6208103 100644 --- a/odb/mssql/error.hxx +++ b/odb/mssql/error.hxx @@ -11,6 +11,8 @@ #include #include // connection #include +#include + #include namespace odb @@ -21,6 +23,9 @@ namespace odb translate_error (connection&); LIBODB_MSSQL_EXPORT void + translate_error (connection&, const auto_handle&); + + LIBODB_MSSQL_EXPORT void translate_error (SQLHANDLE, SQLSMALLINT htype); } } -- cgit v1.1