aboutsummaryrefslogtreecommitdiff
path: root/odb/oracle/error.cxx
diff options
context:
space:
mode:
authorConstantin Michael <constantin@codesynthesis.com>2011-11-29 14:45:51 +0200
committerConstantin Michael <constantin@codesynthesis.com>2011-11-30 11:32:07 +0200
commitc352bdb8b4ee7a636f71a71a301c181942af2d39 (patch)
tree5b7faa4d826a23162a59e241cb800a9f0f7e2db8 /odb/oracle/error.cxx
parent3ed6a781cf4aad7986f805dc8a8e5c487d10a805 (diff)
Improve the Oracle translate_error implementation
The improved implementation scans all the records associated with an error handle. Furthermore, if it is established that the connection to the database has been lost, the connection is marked as such. Additionally, all special exceptions (deadlock, timeout, and connection_lost) are now supported.
Diffstat (limited to 'odb/oracle/error.cxx')
-rw-r--r--odb/oracle/error.cxx173
1 files changed, 143 insertions, 30 deletions
diff --git a/odb/oracle/error.cxx b/odb/oracle/error.cxx
index f00ca19..fe782f4 100644
--- a/odb/oracle/error.cxx
+++ b/odb/oracle/error.cxx
@@ -9,6 +9,7 @@
#include <odb/oracle/error.hxx>
#include <odb/oracle/exceptions.hxx>
+#include <odb/oracle/connection.hxx>
using namespace std;
@@ -17,47 +18,159 @@ namespace odb
namespace oracle
{
void
- translate_error (void* h, ub4 t, sword s)
+ translate_error (void* h, ub4 t, sword s, connection* conn)
{
- assert (s == OCI_ERROR || s == OCI_INVALID_HANDLE);
+ assert (s != OCI_SUCCESS && s != OCI_SUCCESS_WITH_INFO);
- if (s == OCI_INVALID_HANDLE)
- throw invalid_oci_handle ();
+ if (s != OCI_ERROR)
+ {
+ switch (s)
+ {
+ case OCI_STILL_EXECUTING:
+ {
+ throw database_exception (0, "statement still executing");
+ break;
+ }
+ case OCI_NEED_DATA:
+ case OCI_NO_DATA:
+ {
+ throw database_exception (0, "unhandled OCI_*_DATA condition");
+ break;
+ }
+ case OCI_INVALID_HANDLE:
+ {
+ throw invalid_oci_handle ();
+ break;
+ }
+ }
+ }
+ sword r (0);
sb4 e;
- details::buffer b;
- b.capacity (128);
+ char b[512]; // Error message will be truncated if it does not fit.
- bool trunc (true);
- while (trunc)
+ if (t == OCI_HTYPE_ERROR)
{
- trunc = OCIErrorGet (h,
- 1,
- 0,
- &e,
- reinterpret_cast<OraText*> (b.data ()),
- b.capacity (),
- t) == OCI_ERROR;
-
- if (trunc)
- b.capacity (b.capacity () * 2);
+ // Mark the connection as failed if necessary.
+ //
+ if (conn != 0)
+ {
+ OCIServer* server (0);
+ r = OCIAttrGet (conn->handle (),
+ OCI_HTYPE_SVCCTX,
+ &server,
+ 0,
+ OCI_ATTR_SERVER,
+ conn->error_handle ());
+
+ if (r != OCI_SUCCESS)
+ throw invalid_oci_handle ();
+
+ ub4 server_status (0);
+ r = OCIAttrGet (server,
+ OCI_HTYPE_SERVER,
+ &server_status,
+ 0,
+ OCI_ATTR_SERVER_STATUS,
+ conn->error_handle ());
+
+ if (r != OCI_SUCCESS)
+ throw invalid_oci_handle ();
+
+ if (server_status == OCI_SERVER_NOT_CONNECTED)
+ conn->mark_failed ();
+ }
+
+ // We need to translate certain Oracle error codes to special
+ // exceptions, such as deadlock, timeout, etc. The problem is we can
+ // have multiple records potentially with different error 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 (sb4 i (1);; ++i)
+ {
+ r = OCIErrorGet (h, i, 0, &e, reinterpret_cast<OraText*> (b), 512, t);
+
+ if (r == OCI_NO_DATA)
+ break;
+
+ code nc;
+
+ if (e == 60 || // Deadlock detected while waiting for resource.
+ e == 104) // Deadlock detected; all public servers blocked.
+ nc = code_deadlock;
+ else if (e == 51 || // Timeout occurred while waiting for a resource.
+ e == 54) // Resource busy and acquisition timeout expired.
+ nc = code_timeout;
+ else if (e == 28 || // Session has been killed.
+ e == 3135 || // Connection lost contact.
+ e == 3136 || // Inbound connection timed out.
+ e == 3138) // Connection terminated.
+ nc = code_connection_lost;
+ else
+ {
+ c = code_none;
+ break;
+ }
+
+ if (c != code_none && c != nc)
+ {
+ // Several different codes.
+ //
+ c = code_none;
+ break;
+ }
+
+ c = nc;
+ }
+
+ switch (c)
+ {
+ case code_deadlock:
+ throw deadlock ();
+ case code_timeout:
+ throw timeout ();
+ case code_connection_lost:
+ throw connection_lost ();
+ case code_none:
+ break;
+ }
}
- // @@ Need to find a source of OCI specific codes.
+ // Some other error code. Prepare database_exception.
//
- // There are no symbolic definitions for error codes in the OCI
- // header files.
- //
- switch (e)
+ database_exception dbe;
+
+ for (sb4 i (1);; ++i)
{
- case 60:
- throw deadlock ();
- case 3135:
- case 3136:
- throw connection_lost ();
- default:
- throw database_exception (e, b.data ());
+ r = OCIErrorGet (h,
+ i,
+ 0,
+ &e,
+ reinterpret_cast<OraText*> (b),
+ 512,
+ t);
+
+ if (r == OCI_NO_DATA)
+ break;
+
+ dbe.append (e, b);
}
+
+ throw dbe;
}
}
}