aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-11-20 14:57:35 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-11-20 14:57:35 +0200
commita8a2cd61bb9f3657c65acf3a1d9dfaaa68271f4e (patch)
tree47ce1c808a9695050b27f077763efa627049a93a
parent16283f61ddd0525b08e615fac6148f544973ac82 (diff)
Implement support for transactions
-rw-r--r--odb/mssql/connection.cxx22
-rw-r--r--odb/mssql/error.cxx30
-rw-r--r--odb/mssql/error.hxx2
-rw-r--r--odb/mssql/makefile1
-rw-r--r--odb/mssql/transaction-impl.cxx38
-rw-r--r--odb/mssql/transaction.cxx26
-rw-r--r--odb/mssql/transaction.hxx89
-rw-r--r--odb/mssql/transaction.ixx47
8 files changed, 226 insertions, 29 deletions
diff --git a/odb/mssql/connection.cxx b/odb/mssql/connection.cxx
index 788fecb..0d09461 100644
--- a/odb/mssql/connection.cxx
+++ b/odb/mssql/connection.cxx
@@ -10,7 +10,7 @@
#include <odb/mssql/mssql.hxx>
#include <odb/mssql/database.hxx>
#include <odb/mssql/connection.hxx>
-//#include <odb/mssql/transaction.hxx>
+#include <odb/mssql/transaction.hxx>
//#include <odb/mssql/statement.hxx>
//#include <odb/mssql/statement-cache.hxx>
#include <odb/mssql/error.hxx>
@@ -42,6 +42,19 @@ namespace odb
handle_.reset (h);
}
+ // Set the manual commit mode.
+ //
+ r = SQLSetConnectAttr (handle_,
+ SQL_ATTR_AUTOCOMMIT,
+ SQL_AUTOCOMMIT_OFF,
+ SQL_IS_UINTEGER);
+
+ if (!SQL_SUCCEEDED (r))
+ // Still use the handle version of translate_error since there
+ // is no connection yet.
+ //
+ translate_error (r, handle_, SQL_HANDLE_DBC);
+
// Connect.
//
{
@@ -56,9 +69,6 @@ namespace odb
SQL_DRIVER_NOPROMPT);
if (!SQL_SUCCEEDED (r))
- // Still use the handle version of translate_error since there
- // is no connection.
- //
translate_error (r, handle_, SQL_HANDLE_DBC);
state_ = state_connected;
@@ -93,9 +103,7 @@ namespace odb
transaction_impl* connection::
begin ()
{
- //@@
- //return new transaction_impl (connection_ptr (inc_ref (this)));
- return 0;
+ return new transaction_impl (connection_ptr (inc_ref (this)));
}
unsigned long long connection::
diff --git a/odb/mssql/error.cxx b/odb/mssql/error.cxx
index b659bd6..dffe4cf 100644
--- a/odb/mssql/error.cxx
+++ b/odb/mssql/error.cxx
@@ -20,7 +20,8 @@ namespace odb
translate_error (SQLRETURN r,
SQLHANDLE h,
SQLSMALLINT htype,
- connection* conn)
+ connection* conn,
+ bool end_tran)
{
// First see if we have one of the errors indicated via the
// return error code.
@@ -120,6 +121,18 @@ namespace odb
break;
}
+ // If a call to SQLEndTran() fails, then the connection is
+ // put into the so called "suspended state" and should be
+ // disconnected unless we know the transaction was rolled
+ // back. See SQLEndTran() documentation for details.
+ //
+ if (end_tran &&
+ s != "25S03" && // Transaction is rolled back.
+ s != "40001" && // Serialization failure.
+ s != "40002" && // Integrity constraint.
+ s != "HYC00") // Optional feature not implemented.
+ conn->mark_failed ();
+
if (c != code_none && c != nc)
{
// Several different codes.
@@ -173,7 +186,12 @@ namespace odb
string s (sqlstate);
if (s == "08S01" || // Link failure.
- s == "HYT01") // Connection timeout.
+ s == "HYT01" || // Connection timeout.
+ (end_tran &&
+ s != "25S03" &&
+ s != "40001" &&
+ s != "40002" &&
+ s != "HYC00"))
conn->mark_failed ();
}
@@ -191,9 +209,9 @@ namespace odb
}
void
- translate_error (SQLRETURN r, connection& c)
+ translate_error (SQLRETURN r, connection& c, bool end_tran)
{
- translate_error (r, c.handle (), SQL_HANDLE_DBC, &c);
+ translate_error (r, c.handle (), SQL_HANDLE_DBC, &c, end_tran);
}
void
@@ -201,13 +219,13 @@ namespace odb
connection& c,
const auto_handle<SQL_HANDLE_STMT>& h)
{
- translate_error (r, h, SQL_HANDLE_STMT, &c);
+ translate_error (r, h, SQL_HANDLE_STMT, &c, false);
}
void
translate_error (SQLRETURN r, SQLHANDLE h, SQLSMALLINT htype)
{
- translate_error (r, h, htype, 0);
+ translate_error (r, h, htype, 0, false);
}
}
}
diff --git a/odb/mssql/error.hxx b/odb/mssql/error.hxx
index f160514..126f7d9 100644
--- a/odb/mssql/error.hxx
+++ b/odb/mssql/error.hxx
@@ -20,7 +20,7 @@ namespace odb
namespace mssql
{
LIBODB_MSSQL_EXPORT void
- translate_error (SQLRETURN, connection&);
+ translate_error (SQLRETURN, connection&, bool end_tran = false);
LIBODB_MSSQL_EXPORT void
translate_error (SQLRETURN,
diff --git a/odb/mssql/makefile b/odb/mssql/makefile
index 10e9e28..6a2ff51 100644
--- a/odb/mssql/makefile
+++ b/odb/mssql/makefile
@@ -13,6 +13,7 @@ connection-factory.cxx \
database.cxx \
error.cxx \
exceptions.cxx \
+transaction.cxx \
transaction-impl.cxx
diff --git a/odb/mssql/transaction-impl.cxx b/odb/mssql/transaction-impl.cxx
index 4d0d77f..308f078 100644
--- a/odb/mssql/transaction-impl.cxx
+++ b/odb/mssql/transaction-impl.cxx
@@ -5,6 +5,7 @@
#include <odb/tracer.hxx>
+#include <odb/mssql/mssql.hxx>
#include <odb/mssql/database.hxx>
#include <odb/mssql/connection.hxx>
#include <odb/mssql/transaction-impl.hxx>
@@ -34,7 +35,6 @@ namespace odb
void transaction_impl::
start ()
{
- /*
// Grab a connection if we don't already have one.
//
if (connection_ == 0)
@@ -43,57 +43,65 @@ namespace odb
odb::transaction_impl::connection_ = connection_.get ();
}
+ /*
+ @@ TODO
{
odb::tracer* t;
if ((t = connection_->tracer ()) || (t = database_.tracer ()))
t->execute (*connection_, "BEGIN");
}
-
- if (mssql_real_query (connection_->handle (), "begin", 5) != 0)
- translate_error (*connection_);
*/
+
+ // In ODBC a transaction is started automatically before the first
+ // statement is executed.
+ //
}
void transaction_impl::
commit ()
{
/*
- connection_->clear ();
-
+ @@ TODO
{
odb::tracer* t;
if ((t = connection_->tracer ()) || (t = database_.tracer ()))
t->execute (*connection_, "COMMIT");
}
+ */
- if (mssql_real_query (connection_->handle (), "commit", 6) != 0)
- translate_error (*connection_);
+ SQLRETURN r (
+ SQLEndTran (SQL_HANDLE_DBC, connection_->handle (), SQL_COMMIT));
- // Release the connection.
+ if (!SQL_SUCCEEDED (r))
+ translate_error (r, *connection_, true);
+
+ // We cannot release the connection early since we may still need
+ // to free (query) statements.
//
//connection_.reset ();
- */
}
void transaction_impl::
rollback ()
{
/*
- connection_->clear ();
-
+ @@ TODO
{
odb::tracer* t;
if ((t = connection_->tracer ()) || (t = database_.tracer ()))
t->execute (*connection_, "ROLLBACK");
}
+ */
+
+ SQLRETURN r (
+ SQLEndTran (SQL_HANDLE_DBC, connection_->handle (), SQL_ROLLBACK));
- if (mssql_real_query (connection_->handle (), "rollback", 8) != 0)
- translate_error (*connection_);
+ if (!SQL_SUCCEEDED (r))
+ translate_error (r, *connection_, true);
// Release the connection.
//
//connection_.reset ();
- */
}
}
}
diff --git a/odb/mssql/transaction.cxx b/odb/mssql/transaction.cxx
new file mode 100644
index 0000000..d049d2e
--- /dev/null
+++ b/odb/mssql/transaction.cxx
@@ -0,0 +1,26 @@
+// file : odb/mssql/transaction.cxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#include <odb/mssql/transaction.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ transaction& transaction::
+ current ()
+ {
+ // While the impl type can be of the concrete type, the transaction
+ // object can be created as either odb:: or odb::mssql:: type. To
+ // work around that we are going to hard-cast one to the other
+ // relying on the fact that they have the same representation and
+ // no virtual functions. The former is checked in the tests.
+ //
+ odb::transaction& b (odb::transaction::current ());
+ dynamic_cast<transaction_impl&> (b.implementation ());
+ return reinterpret_cast<transaction&> (b);
+ }
+ }
+}
diff --git a/odb/mssql/transaction.hxx b/odb/mssql/transaction.hxx
new file mode 100644
index 0000000..57806b8
--- /dev/null
+++ b/odb/mssql/transaction.hxx
@@ -0,0 +1,89 @@
+// file : odb/mssql/transaction.hxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+//@@ disabled functionality
+
+#ifndef ODB_MSSQL_TRANSACTION_HXX
+#define ODB_MSSQL_TRANSACTION_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/transaction.hxx>
+
+#include <odb/mssql/version.hxx>
+#include <odb/mssql/forward.hxx>
+//#include <odb/mssql/tracer.hxx>
+
+#include <odb/mssql/details/export.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ class transaction_impl;
+
+ class LIBODB_MSSQL_EXPORT transaction: public odb::transaction
+ {
+ public:
+ typedef mssql::database database_type;
+ typedef mssql::connection connection_type;
+
+ explicit
+ transaction (transaction_impl*);
+
+ // Return the database this transaction is on.
+ //
+ database_type&
+ database ();
+
+ // Return the underlying database connection for this transaction.
+ //
+ connection_type&
+ connection ();
+
+ // Return current transaction or throw if there is no transaction
+ // in effect.
+ //
+ static transaction&
+ current ();
+
+ // Set the current thread's transaction.
+ //
+ static void
+ current (transaction&);
+
+ /*
+ // SQL statement tracing.
+ //
+ public:
+ typedef mssql::tracer tracer_type;
+
+ void
+ tracer (tracer_type& t)
+ {
+ odb::transaction::tracer (t);
+ }
+
+ void
+ tracer (tracer_type* t)
+ {
+ odb::transaction::tracer (t);
+ }
+
+ using odb::transaction::tracer;
+ */
+
+ public:
+ transaction_impl&
+ implementation ();
+ };
+ }
+}
+
+#include <odb/mssql/transaction.ixx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_MSSQL_TRANSACTION_HXX
diff --git a/odb/mssql/transaction.ixx b/odb/mssql/transaction.ixx
new file mode 100644
index 0000000..6e4daae
--- /dev/null
+++ b/odb/mssql/transaction.ixx
@@ -0,0 +1,47 @@
+// file : odb/mssql/transaction.ixx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#include <odb/mssql/database.hxx>
+#include <odb/mssql/transaction-impl.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ inline transaction::
+ transaction (transaction_impl* impl)
+ : odb::transaction (impl)
+ {
+ }
+
+ inline transaction_impl& transaction::
+ implementation ()
+ {
+ // We can use static_cast here since we have an instance of
+ // mssql::transaction.
+ //
+ return static_cast<transaction_impl&> (
+ odb::transaction::implementation ());
+ }
+
+ inline transaction::database_type& transaction::
+ database ()
+ {
+ return static_cast<database_type&> (odb::transaction::database ());
+ }
+
+ inline transaction::connection_type& transaction::
+ connection ()
+ {
+ return implementation ().connection ();
+ }
+
+ inline void transaction::
+ current (transaction& t)
+ {
+ odb::transaction::current (t);
+ }
+ }
+}