aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2013-01-14 16:01:06 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2013-01-14 16:01:06 +0200
commit5e113195591a9f8dccbb8f5f743cdd7776906b08 (patch)
tree74eb23894a9a85f3255b95cd7e998a405a6464c5
parent9844c8efeaa64f62e4bfbd739088d93df97d8fc8 (diff)
Add support for MSSQL ROWVERSION
ODB can now use ROWVERSION column as an optimistic concurrency version.
-rw-r--r--odb/mssql/container-statements.hxx2
-rw-r--r--odb/mssql/no-id-object-statements.hxx3
-rw-r--r--odb/mssql/polymorphic-object-statements.hxx6
-rw-r--r--odb/mssql/simple-object-statements.hxx6
-rw-r--r--odb/mssql/statement.cxx116
-rw-r--r--odb/mssql/statement.hxx35
-rw-r--r--odb/mssql/statement.ixx49
7 files changed, 188 insertions, 29 deletions
diff --git a/odb/mssql/container-statements.hxx b/odb/mssql/container-statements.hxx
index 62ee3a2..dcf8e5c 100644
--- a/odb/mssql/container-statements.hxx
+++ b/odb/mssql/container-statements.hxx
@@ -169,7 +169,7 @@ namespace odb
if (insert_one_ == 0)
insert_one_.reset (
new (details::shared) insert_statement_type (
- conn_, insert_one_text_, data_image_binding_, false));
+ conn_, insert_one_text_, data_image_binding_, false, false));
return *insert_one_;
}
diff --git a/odb/mssql/no-id-object-statements.hxx b/odb/mssql/no-id-object-statements.hxx
index 8eae7c7..30ba999 100644
--- a/odb/mssql/no-id-object-statements.hxx
+++ b/odb/mssql/no-id-object-statements.hxx
@@ -87,7 +87,8 @@ namespace odb
conn_,
object_traits::persist_statement,
insert_image_binding_,
- false));
+ false,
+ object_traits::rowversion));
return *persist_;
}
diff --git a/odb/mssql/polymorphic-object-statements.hxx b/odb/mssql/polymorphic-object-statements.hxx
index bc58f6f..c121168 100644
--- a/odb/mssql/polymorphic-object-statements.hxx
+++ b/odb/mssql/polymorphic-object-statements.hxx
@@ -277,12 +277,15 @@ namespace odb
insert_statement_type&
persist_statement ()
{
+ // Auto id and version are in the root.
+ //
if (persist_ == 0)
persist_.reset (
new (details::shared) insert_statement_type (
conn_,
object_traits::persist_statement,
insert_image_binding_,
+ false,
false));
return *persist_;
@@ -313,7 +316,8 @@ namespace odb
new (details::shared) update_statement_type (
conn_,
object_traits::update_statement,
- update_image_binding_));
+ update_image_binding_,
+ false));
return *update_;
}
diff --git a/odb/mssql/simple-object-statements.hxx b/odb/mssql/simple-object-statements.hxx
index fc46f5b..a1f4503 100644
--- a/odb/mssql/simple-object-statements.hxx
+++ b/odb/mssql/simple-object-statements.hxx
@@ -343,7 +343,8 @@ namespace odb
conn_,
object_traits::persist_statement,
insert_image_binding_,
- object_traits::auto_id));
+ object_traits::auto_id,
+ object_traits::rowversion));
return *persist_;
}
@@ -370,7 +371,8 @@ namespace odb
new (details::shared) update_statement_type (
conn_,
object_traits::update_statement,
- update_image_binding_));
+ update_image_binding_,
+ object_traits::rowversion));
return *update_;
}
diff --git a/odb/mssql/statement.cxx b/odb/mssql/statement.cxx
index 524fc06..a0371b5 100644
--- a/odb/mssql/statement.cxx
+++ b/odb/mssql/statement.cxx
@@ -795,12 +795,15 @@ namespace odb
insert_statement (connection_type& conn,
const string& t,
binding& param,
- bool returning)
- : statement (conn, t), returning_ (returning)
+ bool returning_id,
+ bool returning_version)
+ : statement (conn, t),
+ returning_id_ (returning_id),
+ returning_version_ (returning_version)
{
bind_param (param.bind, param.count);
- if (returning)
+ if (returning_id_ || returning_version_)
init_result ();
}
@@ -808,13 +811,16 @@ namespace odb
insert_statement (connection_type& conn,
const char* t,
binding& param,
- bool returning,
+ bool returning_id,
+ bool returning_version,
bool ct)
- : statement (conn, t, ct), returning_ (returning)
+ : statement (conn, t, ct),
+ returning_id_ (returning_id),
+ returning_version_ (returning_version)
{
bind_param (param.bind, param.count);
- if (returning)
+ if (returning_id_ || returning_version_)
init_result ();
}
@@ -831,16 +837,35 @@ namespace odb
batch_ = strstr (text_, "OUTPUT INSERTED.") == 0 &&
strstr (text_, "output inserted.") == 0;
- SQLRETURN r (
- SQLBindCol (stmt_,
- 1,
- SQL_C_SBIGINT,
- (SQLPOINTER) &id_,
- sizeof (id_),
- &id_size_ind_));
+ SQLUSMALLINT col (1);
- if (!SQL_SUCCEEDED (r))
- translate_error (r, conn_, stmt_);
+ if (returning_id_)
+ {
+ SQLRETURN r (
+ SQLBindCol (stmt_,
+ col++,
+ SQL_C_SBIGINT,
+ (SQLPOINTER) &id_,
+ sizeof (id_),
+ &id_size_ind_));
+
+ if (!SQL_SUCCEEDED (r))
+ translate_error (r, conn_, stmt_);
+ }
+
+ if (returning_version_)
+ {
+ SQLRETURN r (
+ SQLBindCol (stmt_,
+ col++,
+ SQL_C_BINARY,
+ (SQLPOINTER) &version_,
+ sizeof (version_),
+ &version_size_ind_));
+
+ if (!SQL_SUCCEEDED (r))
+ translate_error (r, conn_, stmt_);
+ }
}
bool insert_statement::
@@ -902,9 +927,10 @@ namespace odb
translate_error (r, conn_, stmt_);
}
- // Fetch the row containing the id if this statement is returning.
+ // Fetch the row containing the id/version if this statement is
+ // returning.
//
- if (returning_)
+ if (returning_id_ || returning_version_)
{
if (batch_)
{
@@ -953,20 +979,46 @@ namespace odb
}
update_statement::
- update_statement (connection_type& conn, const string& t, binding& param)
- : statement (conn, t)
+ update_statement (connection_type& conn,
+ const string& t,
+ binding& param,
+ bool returning_version)
+ : statement (conn, t), returning_version_ (returning_version)
{
bind_param (param.bind, param.count);
+
+ if (returning_version_)
+ init_result ();
}
update_statement::
update_statement (connection_type& conn,
const char* t,
binding& param,
+ bool returning_version,
bool ct)
- : statement (conn, t, ct)
+ : statement (conn, t, ct),
+ returning_version_ (returning_version)
{
bind_param (param.bind, param.count);
+
+ if (returning_version_)
+ init_result ();
+ }
+
+ void update_statement::
+ init_result ()
+ {
+ SQLRETURN r (
+ SQLBindCol (stmt_,
+ 1,
+ SQL_C_BINARY,
+ (SQLPOINTER) &version_,
+ sizeof (version_),
+ &version_size_ind_));
+
+ if (!SQL_SUCCEEDED (r))
+ translate_error (r, conn_, stmt_);
}
unsigned long long update_statement::
@@ -990,6 +1042,30 @@ namespace odb
if (!SQL_SUCCEEDED (r))
translate_error (r, conn_, stmt_);
+ // Fetch the row containing the id/version if this statement is
+ // returning.
+ //
+ if (returning_version_)
+ {
+ r = SQLFetch (stmt_);
+
+ if (r != SQL_NO_DATA && !SQL_SUCCEEDED (r))
+ translate_error (r, conn_, stmt_);
+
+ {
+ SQLRETURN r (SQLCloseCursor (stmt_)); // Don't overwrite r.
+
+ if (!SQL_SUCCEEDED (r))
+ translate_error (r, conn_, stmt_);
+ }
+
+ if (r == SQL_NO_DATA)
+ throw database_exception (
+ 0,
+ "?????",
+ "result set expected from a statement with the OUTPUT clause");
+ }
+
return static_cast<unsigned long long> (rows);
}
diff --git a/odb/mssql/statement.hxx b/odb/mssql/statement.hxx
index 4b54097..e51cd3c 100644
--- a/odb/mssql/statement.hxx
+++ b/odb/mssql/statement.hxx
@@ -200,12 +200,14 @@ namespace odb
insert_statement (connection_type& conn,
const std::string& text,
binding& param,
- bool returning);
+ bool returning_id,
+ bool returning_version);
insert_statement (connection_type& conn,
const char* text,
binding& param,
- bool returning,
+ bool returning_id,
+ bool returning_version,
bool copy_text = true);
// Return true if successful and false if the row is a duplicate.
@@ -220,6 +222,9 @@ namespace odb
return id_;
}
+ unsigned long long
+ version ();
+
private:
insert_statement (const insert_statement&);
insert_statement& operator= (const insert_statement&);
@@ -229,10 +234,15 @@ namespace odb
init_result ();
private:
- bool returning_;
+ bool returning_id_;
+ bool returning_version_;
bool batch_;
+
unsigned long long id_;
SQLLEN id_size_ind_;
+
+ unsigned char version_[8];
+ SQLLEN version_size_ind_;
};
class LIBODB_MSSQL_EXPORT update_statement: public statement
@@ -243,19 +253,34 @@ namespace odb
update_statement (connection_type& conn,
const std::string& text,
- binding& param);
+ binding& param,
+ bool returning_version);
update_statement (connection_type& conn,
const char* text,
binding& param,
+ bool returning_version,
bool copy_text = true);
unsigned long long
execute ();
+ unsigned long long
+ version ();
+
private:
update_statement (const update_statement&);
update_statement& operator= (const update_statement&);
+
+ private:
+ void
+ init_result ();
+
+ private:
+ bool returning_version_;
+
+ unsigned char version_[8];
+ SQLLEN version_size_ind_;
};
class LIBODB_MSSQL_EXPORT delete_statement: public statement
@@ -283,6 +308,8 @@ namespace odb
}
}
+#include <odb/mssql/statement.ixx>
+
#include <odb/post.hxx>
#endif // ODB_MSSQL_STATEMENT_HXX
diff --git a/odb/mssql/statement.ixx b/odb/mssql/statement.ixx
new file mode 100644
index 0000000..d27e961
--- /dev/null
+++ b/odb/mssql/statement.ixx
@@ -0,0 +1,49 @@
+// file : odb/mssql/statement.ixx
+// copyright : Copyright (c) 2005-2012 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace mssql
+ {
+ inline unsigned long long insert_statement::
+ version ()
+ {
+ unsigned long long r;
+
+ // The value is in the big-endian format.
+ //
+ unsigned char* p (reinterpret_cast<unsigned char*> (&r));
+ p[0] = version_[7];
+ p[1] = version_[6];
+ p[2] = version_[5];
+ p[3] = version_[4];
+ p[4] = version_[3];
+ p[5] = version_[2];
+ p[6] = version_[1];
+ p[7] = version_[0];
+
+ return r;
+ }
+
+ inline unsigned long long update_statement::
+ version ()
+ {
+ unsigned long long r;
+
+ // The value is in the big-endian format.
+ //
+ unsigned char* p (reinterpret_cast<unsigned char*> (&r));
+ p[0] = version_[7];
+ p[1] = version_[6];
+ p[2] = version_[5];
+ p[3] = version_[4];
+ p[4] = version_[3];
+ p[5] = version_[2];
+ p[6] = version_[1];
+ p[7] = version_[0];
+
+ return r;
+ }
+ }
+}