aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-11-29 08:52:28 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-11-29 08:52:28 +0200
commit9d3bf60e2d1f063abd39197b7e60bf6d2bc95aa7 (patch)
tree4a12c0bd029f8e04a383ed905157f70e764ac165
parent91c962e4615101e14be4c720fc386878ddb598a4 (diff)
Add object/view/container statements, statements cache
-rw-r--r--odb/mssql/connection.cxx12
-rw-r--r--odb/mssql/connection.hxx6
-rw-r--r--odb/mssql/container-statements.hxx256
-rw-r--r--odb/mssql/container-statements.txx58
-rw-r--r--odb/mssql/makefile2
-rw-r--r--odb/mssql/object-statements.cxx17
-rw-r--r--odb/mssql/object-statements.hxx606
-rw-r--r--odb/mssql/object-statements.ixx70
-rw-r--r--odb/mssql/object-statements.txx168
-rw-r--r--odb/mssql/statement-cache.hxx87
-rw-r--r--odb/mssql/statements-base.cxx17
-rw-r--r--odb/mssql/statements-base.hxx51
-rw-r--r--odb/mssql/view-statements.hxx83
-rw-r--r--odb/mssql/view-statements.txx33
14 files changed, 1454 insertions, 12 deletions
diff --git a/odb/mssql/connection.cxx b/odb/mssql/connection.cxx
index 1609b80..03b8deb 100644
--- a/odb/mssql/connection.cxx
+++ b/odb/mssql/connection.cxx
@@ -3,16 +3,14 @@
// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
// license : ODB NCUEL; see accompanying LICENSE file
-//@@ disabled functionality
-
#include <string>
#include <odb/mssql/mssql.hxx>
#include <odb/mssql/database.hxx>
#include <odb/mssql/connection.hxx>
#include <odb/mssql/transaction.hxx>
-//#include <odb/mssql/statement.hxx>
-//#include <odb/mssql/statement-cache.hxx>
+#include <odb/mssql/statement.hxx>
+#include <odb/mssql/statement-cache.hxx>
#include <odb/mssql/error.hxx>
using namespace std;
@@ -26,7 +24,7 @@ namespace odb
: odb::connection (db),
db_ (db),
state_ (state_disconnected),
- // statement_cache_ (new statement_cache_type (*this))
+ statement_cache_ (new statement_cache_type (*this)),
long_buffer_ (0)
{
SQLRETURN r;
@@ -96,7 +94,7 @@ namespace odb
db_ (db),
handle_ (handle),
state_ (state_connected),
- // statement_cache_ (new statement_cache_type (*this))
+ statement_cache_ (new statement_cache_type (*this)),
long_buffer_ (0)
{
}
@@ -106,7 +104,7 @@ namespace odb
{
// Deallocate prepared statements before we close the connection.
//
- //statement_cache_.reset ();
+ statement_cache_.reset ();
if (state_ != state_disconnected)
SQLDisconnect (handle_); // Ignore any errors.
diff --git a/odb/mssql/connection.hxx b/odb/mssql/connection.hxx
index c38692b..73c00fd 100644
--- a/odb/mssql/connection.hxx
+++ b/odb/mssql/connection.hxx
@@ -3,8 +3,6 @@
// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
// license : ODB NCUEL; see accompanying LICENSE file
-//@@ disabled functionality
-
#ifndef ODB_MSSQL_CONNECTION_HXX
#define ODB_MSSQL_CONNECTION_HXX
@@ -103,13 +101,11 @@ namespace odb
return handle_;
}
- /*
statement_cache_type&
statement_cache ()
{
return *statement_cache_;
}
- */
details::buffer&
long_buffer ()
@@ -137,7 +133,7 @@ namespace odb
//
auto_handle<SQL_HANDLE_STMT> direct_stmt_;
- //std::auto_ptr<statement_cache_type> statement_cache_;
+ std::auto_ptr<statement_cache_type> statement_cache_;
details::buffer long_buffer_;
};
diff --git a/odb/mssql/container-statements.hxx b/odb/mssql/container-statements.hxx
new file mode 100644
index 0000000..6d9dd56
--- /dev/null
+++ b/odb/mssql/container-statements.hxx
@@ -0,0 +1,256 @@
+// file : odb/mssql/container-statements.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#ifndef ODB_MSSQL_CONTAINER_STATEMENTS_HXX
+#define ODB_MSSQL_CONTAINER_STATEMENTS_HXX
+
+#include <odb/pre.hxx>
+
+#include <cstddef> // std::size_t
+
+#include <odb/forward.hxx>
+#include <odb/traits.hxx>
+
+#include <odb/mssql/version.hxx>
+#include <odb/mssql/mssql-types.hxx>
+#include <odb/mssql/statement.hxx>
+
+#include <odb/mssql/details/export.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ class connection;
+
+ // Template argument is the generated abstract container traits type.
+ // That is, it doesn't need to provide column counts and statements.
+ //
+ template <typename T>
+ class container_statements
+ {
+ public:
+ typedef T traits;
+
+ typedef typename traits::data_image_type data_image_type;
+ typedef typename traits::cond_image_type cond_image_type;
+
+ typedef typename traits::functions_type functions_type;
+
+ typedef mssql::insert_statement insert_statement_type;
+ typedef mssql::select_statement select_statement_type;
+ typedef mssql::delete_statement delete_statement_type;
+
+ typedef mssql::connection connection_type;
+
+ container_statements (connection_type&);
+
+ connection_type&
+ connection ()
+ {
+ return conn_;
+ }
+
+ // Functions.
+ //
+ functions_type&
+ functions ()
+ {
+ return functions_;
+ }
+
+ // Id image binding (external).
+ //
+ const binding&
+ id_binding ()
+ {
+ return *id_binding_;
+ }
+
+ void
+ id_binding (const binding& b)
+ {
+ id_binding_ = &b;
+ }
+
+ // Condition image.
+ //
+ cond_image_type&
+ cond_image ()
+ {
+ return cond_image_;
+ }
+
+ std::size_t
+ cond_image_version () const
+ {
+ return cond_image_version_;
+ }
+
+ void
+ cond_image_version (std::size_t v)
+ {
+ cond_image_version_ = v;
+ }
+
+ std::size_t
+ cond_id_binding_version () const
+ {
+ return cond_id_binding_version_;
+ }
+
+ void
+ cond_id_binding_version (std::size_t v)
+ {
+ cond_id_binding_version_ = v;
+ }
+
+ binding&
+ cond_image_binding ()
+ {
+ return cond_image_binding_;
+ }
+
+ // Data image.
+ //
+ data_image_type&
+ data_image ()
+ {
+ return data_image_;
+ }
+
+ std::size_t
+ data_image_version () const
+ {
+ return data_image_version_;
+ }
+
+ void
+ data_image_version (std::size_t v)
+ {
+ data_image_version_ = v;
+ }
+
+ std::size_t
+ data_id_binding_version () const
+ {
+ return data_id_binding_version_;
+ }
+
+ void
+ data_id_binding_version (std::size_t v)
+ {
+ data_id_binding_version_ = v;
+ }
+
+ binding&
+ data_image_binding ()
+ {
+ return data_image_binding_;
+ }
+
+ //
+ // Statements.
+ //
+
+ insert_statement_type&
+ insert_one_statement ()
+ {
+ // Containers never use auto ids so hardcode the insert_statement
+ // constructors returning argument as false.
+ //
+ if (insert_one_ == 0)
+ insert_one_.reset (
+ new (details::shared) insert_statement_type (
+ conn_, insert_one_text_, data_image_binding_, false));
+
+ return *insert_one_;
+ }
+
+ select_statement_type&
+ select_all_statement ()
+ {
+ if (select_all_ == 0)
+ select_all_.reset (
+ new (details::shared) select_statement_type (
+ conn_,
+ select_all_text_,
+ cond_image_binding_,
+ data_image_binding_,
+ 4096)); // Hardcode a 4kB LOB prefetch size.
+
+ return *select_all_;
+ }
+
+ delete_statement_type&
+ delete_all_statement ()
+ {
+ if (delete_all_ == 0)
+ delete_all_.reset (
+ new (details::shared) delete_statement_type (
+ conn_, delete_all_text_, cond_image_binding_));
+
+ return *delete_all_;
+ }
+
+ private:
+ container_statements (const container_statements&);
+ container_statements& operator= (const container_statements&);
+
+ protected:
+ connection_type& conn_;
+ functions_type functions_;
+
+ const binding* id_binding_;
+
+ cond_image_type cond_image_;
+ std::size_t cond_image_version_;
+ std::size_t cond_id_binding_version_;
+ binding cond_image_binding_;
+ bind* cond_image_bind_;
+
+ data_image_type data_image_;
+ std::size_t data_image_version_;
+ std::size_t data_id_binding_version_;
+ binding data_image_binding_;
+ bind* data_image_bind_;
+
+ const char* insert_one_text_;
+ const char* select_all_text_;
+ const char* delete_all_text_;
+
+ details::shared_ptr<insert_statement_type> insert_one_;
+ details::shared_ptr<select_statement_type> select_all_;
+ details::shared_ptr<delete_statement_type> delete_all_;
+ };
+
+ // Template argument is the generated concrete container traits type.
+ //
+ template <typename T>
+ class container_statements_impl: public T::statements_type
+ {
+ public:
+ typedef T traits;
+ typedef typename T::statements_type base;
+ typedef mssql::connection connection_type;
+
+ container_statements_impl (connection_type&);
+
+ private:
+ container_statements_impl (const container_statements_impl&);
+ container_statements_impl& operator= (const container_statements_impl&);
+
+ private:
+ bind cond_image_bind_array_[traits::cond_column_count];
+ bind data_image_bind_array_[traits::data_column_count];
+ };
+ }
+}
+
+#include <odb/mssql/container-statements.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_MSSQL_CONTAINER_STATEMENTS_HXX
diff --git a/odb/mssql/container-statements.txx b/odb/mssql/container-statements.txx
new file mode 100644
index 0000000..cc240bb
--- /dev/null
+++ b/odb/mssql/container-statements.txx
@@ -0,0 +1,58 @@
+// file : odb/mssql/container-statements.txx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#include <cstring> // std::memset
+
+namespace odb
+{
+ namespace mssql
+ {
+ // container_statements
+ //
+
+ template <typename T>
+ container_statements<T>::
+ container_statements (connection_type& conn)
+ : conn_ (conn),
+ functions_ (this,
+ &traits::insert_one,
+ &traits::load_all,
+ &traits::delete_all),
+ id_binding_ (0),
+ cond_image_binding_ (0, 0), // Initialized by impl.
+ data_image_binding_ (0, 0) // Initialized by impl.
+ {
+ cond_image_.version = 0;
+ cond_image_version_ = 0;
+ cond_id_binding_version_ = 0;
+
+ data_image_.version = 0;
+ data_image_version_ = 0;
+ data_id_binding_version_ = 0;
+ }
+
+ template <typename T>
+ container_statements_impl<T>::
+ container_statements_impl (connection_type& conn)
+ : base (conn)
+ {
+ this->cond_image_bind_ = cond_image_bind_array_;
+ this->data_image_bind_ = data_image_bind_array_;
+
+ this->cond_image_binding_.bind = this->cond_image_bind_;
+ this->cond_image_binding_.count = traits::cond_column_count;
+
+ this->data_image_binding_.bind = this->data_image_bind_;
+ this->data_image_binding_.count = traits::data_column_count;
+
+ std::memset (cond_image_bind_array_, 0, sizeof (cond_image_bind_array_));
+ std::memset (data_image_bind_array_, 0, sizeof (data_image_bind_array_));
+
+ this->insert_one_text_ = traits::insert_one_statement;
+ this->select_all_text_ = traits::select_all_statement;
+ this->delete_all_text_ = traits::delete_all_statement;
+ }
+ }
+}
diff --git a/odb/mssql/makefile b/odb/mssql/makefile
index 4758abf..acdeb76 100644
--- a/odb/mssql/makefile
+++ b/odb/mssql/makefile
@@ -13,7 +13,9 @@ connection-factory.cxx \
database.cxx \
error.cxx \
exceptions.cxx \
+object-statements.cxx \
statement.cxx \
+statements-base.cxx \
tracer.cxx \
transaction.cxx \
transaction-impl.cxx
diff --git a/odb/mssql/object-statements.cxx b/odb/mssql/object-statements.cxx
new file mode 100644
index 0000000..2d29c1c
--- /dev/null
+++ b/odb/mssql/object-statements.cxx
@@ -0,0 +1,17 @@
+// file : odb/mssql/object-statements.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#include <odb/mssql/object-statements.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ object_statements_base::
+ ~object_statements_base ()
+ {
+ }
+ }
+}
diff --git a/odb/mssql/object-statements.hxx b/odb/mssql/object-statements.hxx
new file mode 100644
index 0000000..6ab30ec
--- /dev/null
+++ b/odb/mssql/object-statements.hxx
@@ -0,0 +1,606 @@
+// file : odb/mssql/object-statements.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#ifndef ODB_MSSQL_OBJECT_STATEMENTS_HXX
+#define ODB_MSSQL_OBJECT_STATEMENTS_HXX
+
+#include <odb/pre.hxx>
+
+#include <vector>
+#include <cassert>
+#include <cstddef> // std::size_t
+
+#include <odb/forward.hxx>
+#include <odb/traits.hxx>
+#include <odb/cache-traits.hxx>
+
+#include <odb/details/shared-ptr.hxx>
+
+#include <odb/mssql/version.hxx>
+#include <odb/mssql/forward.hxx>
+#include <odb/mssql/mssql-types.hxx>
+#include <odb/mssql/statement.hxx>
+#include <odb/mssql/statements-base.hxx>
+
+#include <odb/mssql/details/export.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ template <typename T>
+ class object_statements;
+
+ template <typename T>
+ class object_statements_no_id;
+
+ template <typename T, typename ID = typename object_traits<T>::id_type>
+ struct object_statements_selector
+ {
+ typedef object_statements<T> type;
+ };
+
+ template <typename T>
+ struct object_statements_selector<T, void>
+ {
+ typedef object_statements_no_id<T> type;
+ };
+
+ //
+ // Implementation for objects with object id.
+ //
+
+ class LIBODB_MSSQL_EXPORT object_statements_base: public statements_base
+ {
+ // Locking.
+ //
+ public:
+ void
+ lock ()
+ {
+ assert (!locked_);
+ locked_ = true;
+ }
+
+ void
+ unlock ()
+ {
+ assert (locked_);
+ locked_ = false;
+ }
+
+ bool
+ locked () const
+ {
+ return locked_;
+ }
+
+ public:
+ virtual
+ ~object_statements_base ();
+
+ protected:
+ object_statements_base (connection_type& conn)
+ : statements_base (conn), locked_ (false)
+ {
+ }
+
+ struct auto_unlock
+ {
+ // Unlocks the statement on construction and re-locks it on
+ // destruction.
+ //
+ auto_unlock (object_statements_base&);
+ ~auto_unlock ();
+
+ private:
+ auto_unlock (const auto_unlock&);
+ auto_unlock& operator= (const auto_unlock&);
+
+ private:
+ object_statements_base& s_;
+ };
+
+ protected:
+ bool locked_;
+ };
+
+ template <typename T, bool optimistic>
+ struct optimistic_data;
+
+ template <typename T>
+ struct optimistic_data<T, true>
+ {
+ typedef T object_type;
+ typedef odb::object_traits<object_type> object_traits;
+
+ optimistic_data (bind*);
+
+ // The id + optimistic column binding.
+ //
+ std::size_t id_image_version_;
+ binding id_image_binding_;
+
+ details::shared_ptr<delete_statement> erase_;
+ };
+
+ template <typename T>
+ struct optimistic_data<T, false>
+ {
+ optimistic_data (bind*) {}
+ };
+
+ template <typename T>
+ class object_statements: public object_statements_base
+ {
+ public:
+ typedef T object_type;
+ typedef odb::object_traits<object_type> object_traits;
+ typedef typename object_traits::id_type id_type;
+ typedef typename object_traits::pointer_type pointer_type;
+ typedef typename object_traits::image_type image_type;
+ typedef typename object_traits::id_image_type id_image_type;
+
+ typedef pointer_cache_traits<pointer_type> object_cache_traits;
+
+ typedef
+ typename object_traits::container_statement_cache_type
+ container_statement_cache_type;
+
+ typedef mssql::insert_statement insert_statement_type;
+ typedef mssql::select_statement select_statement_type;
+ typedef mssql::update_statement update_statement_type;
+ typedef mssql::delete_statement delete_statement_type;
+
+ // Automatic lock.
+ //
+ struct auto_lock
+ {
+ // Lock the statements unless they are already locked in which
+ // case subsequent calls to locked() will return false.
+ //
+ auto_lock (object_statements&);
+
+ // Unlock the statements if we are holding the lock and clear
+ // the delayed loads. This should only happen in case an
+ // exception is thrown. In normal circumstances, the user
+ // should call unlock() explicitly.
+ //
+ ~auto_lock ();
+
+ // Return true if this auto_lock instance holds the lock.
+ //
+ bool
+ locked () const;
+
+ // Unlock the statements.
+ //
+ void
+ unlock ();
+
+ private:
+ auto_lock (const auto_lock&);
+ auto_lock& operator= (const auto_lock&);
+
+ private:
+ object_statements& s_;
+ bool locked_;
+ };
+
+ public:
+ object_statements (connection_type&);
+
+ virtual
+ ~object_statements ();
+
+ // Delayed loading.
+ //
+ void
+ delay_load (const id_type& id,
+ object_type& obj,
+ const typename object_cache_traits::position_type& p)
+ {
+ delayed_.push_back (delayed_load (id, obj, p));
+ }
+
+ void
+ load_delayed ()
+ {
+ assert (locked ());
+
+ if (!delayed_.empty ())
+ load_delayed_ ();
+ }
+
+ void
+ clear_delayed ()
+ {
+ if (!delayed_.empty ())
+ clear_delayed_ ();
+ }
+
+ // Object image.
+ //
+ image_type&
+ image ()
+ {
+ return image_;
+ }
+
+ // Insert binding.
+ //
+ std::size_t
+ insert_image_version () const { return insert_image_version_;}
+
+ void
+ insert_image_version (std::size_t v) {insert_image_version_ = v;}
+
+ binding&
+ insert_image_binding () {return insert_image_binding_;}
+
+ // Update binding.
+ //
+ std::size_t
+ update_image_version () const { return update_image_version_;}
+
+ void
+ update_image_version (std::size_t v) {update_image_version_ = v;}
+
+ std::size_t
+ update_id_image_version () const { return update_id_image_version_;}
+
+ void
+ update_id_image_version (std::size_t v) {update_id_image_version_ = v;}
+
+ binding&
+ update_image_binding () {return update_image_binding_;}
+
+ // Select binding.
+ //
+ std::size_t
+ select_image_version () const { return select_image_version_;}
+
+ void
+ select_image_version (std::size_t v) {select_image_version_ = v;}
+
+ binding&
+ select_image_binding () {return select_image_binding_;}
+
+ // Object id image and binding.
+ //
+ id_image_type&
+ id_image () {return id_image_;}
+
+ std::size_t
+ id_image_version () const {return id_image_version_;}
+
+ void
+ id_image_version (std::size_t v) {id_image_version_ = v;}
+
+ binding&
+ id_image_binding () {return id_image_binding_;}
+
+ // Optimistic id + managed column image binding.
+ //
+ std::size_t
+ optimistic_id_image_version () const {return od_.id_image_version_;}
+
+ void
+ optimistic_id_image_version (std::size_t v) {od_.id_image_version_ = v;}
+
+ binding&
+ optimistic_id_image_binding () {return od_.id_image_binding_;}
+
+ // Statements.
+ //
+ insert_statement_type&
+ persist_statement ()
+ {
+ if (persist_ == 0)
+ persist_.reset (
+ new (details::shared) insert_statement_type (
+ conn_,
+ object_traits::persist_statement,
+ insert_image_binding_,
+ object_traits::auto_id));
+
+ return *persist_;
+ }
+
+ select_statement_type&
+ find_statement ()
+ {
+ if (find_ == 0)
+ find_.reset (
+ new (details::shared) select_statement_type (
+ conn_,
+ object_traits::find_statement,
+ id_image_binding_,
+ select_image_binding_));
+
+ return *find_;
+ }
+
+ update_statement_type&
+ update_statement ()
+ {
+ if (update_ == 0)
+ update_.reset (
+ new (details::shared) update_statement_type (
+ conn_,
+ object_traits::update_statement,
+ update_image_binding_));
+
+ return *update_;
+ }
+
+ delete_statement_type&
+ erase_statement ()
+ {
+ if (erase_ == 0)
+ erase_.reset (
+ new (details::shared) delete_statement_type (
+ conn_,
+ object_traits::erase_statement,
+ id_image_binding_));
+
+ return *erase_;
+ }
+
+ delete_statement_type&
+ optimistic_erase_statement ()
+ {
+ if (od_.erase_ == 0)
+ {
+ od_.erase_.reset (
+ new (details::shared) delete_statement_type (
+ conn_,
+ object_traits::optimistic_erase_statement,
+ od_.id_image_binding_));
+ }
+
+ return *od_.erase_;
+ }
+
+ // Container statement cache.
+ //
+ container_statement_cache_type&
+ container_statment_cache ()
+ {
+ return container_statement_cache_;
+ }
+
+ private:
+ object_statements (const object_statements&);
+ object_statements& operator= (const object_statements&);
+
+ private:
+ void
+ load_delayed_ ();
+
+ void
+ clear_delayed_ ();
+
+ private:
+ // select = total
+ // insert = total - inverse - managed_optimistic - auto_id
+ // update = total - inverse - managed_optimistic - id - readonly
+ //
+ static const std::size_t id_column_count =
+ object_traits::id_column_count;
+
+ static const std::size_t managed_optimistic_column_count =
+ object_traits::managed_optimistic_column_count;
+
+ static const std::size_t select_column_count =
+ object_traits::column_count;
+
+ static const std::size_t insert_column_count =
+ object_traits::column_count - object_traits::inverse_column_count -
+ object_traits::managed_optimistic_column_count -
+ (object_traits::auto_id ? id_column_count : 0);
+
+ static const std::size_t update_column_count = insert_column_count -
+ (object_traits::auto_id ? 0 : object_traits::id_column_count) -
+ object_traits::readonly_column_count;
+
+ private:
+ container_statement_cache_type container_statement_cache_;
+
+ image_type image_;
+
+ // Select binding.
+ //
+ std::size_t select_image_version_;
+ binding select_image_binding_;
+ bind select_image_bind_[select_column_count];
+
+ // Insert binding.
+ //
+ std::size_t insert_image_version_;
+ binding insert_image_binding_;
+ bind insert_image_bind_[
+ insert_column_count != 0 ? insert_column_count : 1];
+
+ // Update binding. Note that the id suffix is bound to id_image_
+ // below instead of image_ which makes this binding effectively
+ // bound to two images. As a result, we have to track versions
+ // for both of them. If this object uses optimistic concurrency,
+ // then the binding for the managed column (version, timestamp,
+ // etc) comes after the id and the image for such a column is
+ // stored as part of the id image.
+ //
+ std::size_t update_image_version_;
+ std::size_t update_id_image_version_;
+ binding update_image_binding_;
+ bind update_image_bind_[update_column_count + id_column_count +
+ managed_optimistic_column_count];
+
+ // Id image binding (only used as a parameter). Uses the suffix in
+ // the update bind.
+ //
+ id_image_type id_image_;
+ std::size_t id_image_version_;
+ binding id_image_binding_;
+
+ // Extra data for objects with optimistic concurrency support.
+ //
+ optimistic_data<T, managed_optimistic_column_count != 0> od_;
+
+ details::shared_ptr<insert_statement_type> persist_;
+ details::shared_ptr<select_statement_type> find_;
+ details::shared_ptr<update_statement_type> update_;
+ details::shared_ptr<delete_statement_type> erase_;
+
+ // Delayed loading.
+ //
+ struct delayed_load
+ {
+ typedef typename object_cache_traits::position_type position_type;
+
+ delayed_load () {}
+ delayed_load (const id_type& i, object_type& o, const position_type& p)
+ : id (i), obj (&o), pos (p)
+ {
+ }
+
+ id_type id;
+ object_type* obj;
+ position_type pos;
+ };
+
+ typedef std::vector<delayed_load> delayed_loads;
+ delayed_loads delayed_;
+
+ // Delayed vectors swap guard. See the load_delayed_() function for
+ // details.
+ //
+ struct swap_guard
+ {
+ swap_guard (object_statements& os, delayed_loads& dl)
+ : os_ (os), dl_ (dl)
+ {
+ dl_.swap (os_.delayed_);
+ }
+
+ ~swap_guard ()
+ {
+ os_.clear_delayed ();
+ dl_.swap (os_.delayed_);
+ }
+
+ private:
+ object_statements& os_;
+ delayed_loads& dl_;
+ };
+ };
+
+ //
+ // Implementation for objects without object id.
+ //
+
+ template <typename T>
+ class object_statements_no_id: public statements_base
+ {
+ public:
+ typedef T object_type;
+ typedef odb::object_traits<object_type> object_traits;
+ typedef typename object_traits::pointer_type pointer_type;
+ typedef typename object_traits::image_type image_type;
+
+ typedef mssql::insert_statement insert_statement_type;
+
+ public:
+ object_statements_no_id (connection_type&);
+
+ virtual
+ ~object_statements_no_id ();
+
+ // Object image.
+ //
+ image_type&
+ image ()
+ {
+ return image_;
+ }
+
+ // Insert binding.
+ //
+ std::size_t
+ insert_image_version () const { return insert_image_version_;}
+
+ void
+ insert_image_version (std::size_t v) {insert_image_version_ = v;}
+
+ binding&
+ insert_image_binding () {return insert_image_binding_;}
+
+ // Select binding (needed for query support).
+ //
+ std::size_t
+ select_image_version () const { return select_image_version_;}
+
+ void
+ select_image_version (std::size_t v) {select_image_version_ = v;}
+
+ binding&
+ select_image_binding () {return select_image_binding_;}
+
+ // Statements.
+ //
+ insert_statement_type&
+ persist_statement ()
+ {
+ if (persist_ == 0)
+ persist_.reset (
+ new (details::shared) insert_statement_type (
+ conn_,
+ object_traits::persist_statement,
+ insert_image_binding_,
+ false));
+
+ return *persist_;
+ }
+
+ private:
+ object_statements_no_id (const object_statements_no_id&);
+ object_statements_no_id& operator= (const object_statements_no_id&);
+
+ private:
+ // select = total
+ // insert = total - inverse; inverse == 0 for object without id
+ //
+ static const std::size_t insert_column_count =
+ object_traits::column_count;
+
+ static const std::size_t select_column_count =
+ object_traits::column_count;
+
+ private:
+ image_type image_;
+
+ // Select binding.
+ //
+ std::size_t select_image_version_;
+ binding select_image_binding_;
+ bind select_image_bind_[select_column_count];
+
+ // Insert binding.
+ //
+ std::size_t insert_image_version_;
+ binding insert_image_binding_;
+ bind insert_image_bind_[insert_column_count];
+
+ details::shared_ptr<insert_statement_type> persist_;
+ };
+ }
+}
+
+#include <odb/mssql/object-statements.ixx>
+#include <odb/mssql/object-statements.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_MSSQL_OBJECT_STATEMENTS_HXX
diff --git a/odb/mssql/object-statements.ixx b/odb/mssql/object-statements.ixx
new file mode 100644
index 0000000..722bfd0
--- /dev/null
+++ b/odb/mssql/object-statements.ixx
@@ -0,0 +1,70 @@
+// file : odb/mssql/object-statements.ixx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace mssql
+ {
+ //
+ // auto_unlock
+ //
+ inline object_statements_base::auto_unlock::
+ auto_unlock (object_statements_base& s)
+ : s_ (s)
+ {
+ s_.unlock ();
+ }
+
+ inline object_statements_base::auto_unlock::
+ ~auto_unlock ()
+ {
+ s_.lock ();
+ }
+
+ //
+ // auto_lock
+ //
+ template <typename T>
+ inline object_statements<T>::auto_lock::
+ auto_lock (object_statements& s)
+ : s_ (s)
+ {
+ if (!s_.locked ())
+ {
+ s_.lock ();
+ locked_ = true;
+ }
+ else
+ locked_ = false;
+ }
+
+ template <typename T>
+ inline object_statements<T>::auto_lock::
+ ~auto_lock ()
+ {
+ if (locked_)
+ {
+ s_.unlock ();
+ s_.clear_delayed ();
+ }
+ }
+
+ template <typename T>
+ inline bool object_statements<T>::auto_lock::
+ locked () const
+ {
+ return locked_;
+ }
+
+ template <typename T>
+ inline void object_statements<T>::auto_lock::
+ unlock ()
+ {
+ assert (locked_);
+ s_.unlock ();
+ locked_ = false;
+ }
+ }
+}
diff --git a/odb/mssql/object-statements.txx b/odb/mssql/object-statements.txx
new file mode 100644
index 0000000..ebdad67
--- /dev/null
+++ b/odb/mssql/object-statements.txx
@@ -0,0 +1,168 @@
+// file : odb/mssql/object-statements.txx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#include <cstring> // std::memset
+
+#include <odb/session.hxx>
+#include <odb/callback.hxx>
+#include <odb/exceptions.hxx>
+
+#include <odb/mssql/connection.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ //
+ // optimistic_data
+ //
+
+ template <typename T>
+ optimistic_data<T, true>::
+ optimistic_data (bind* b)
+ : id_image_binding_ (
+ b,
+ object_traits::id_column_count +
+ object_traits::managed_optimistic_column_count)
+ {
+ id_image_version_ = 0;
+ }
+
+ //
+ // object_statements
+ //
+
+ template <typename T>
+ object_statements<T>::
+ ~object_statements ()
+ {
+ }
+
+ template <typename T>
+ object_statements<T>::
+ object_statements (connection_type& conn)
+ : object_statements_base (conn),
+ container_statement_cache_ (conn),
+ select_image_binding_ (select_image_bind_, select_column_count),
+ insert_image_binding_ (insert_image_bind_, insert_column_count),
+ update_image_binding_ (update_image_bind_,
+ update_column_count + id_column_count +
+ managed_optimistic_column_count),
+ id_image_binding_ (update_image_bind_ + update_column_count,
+ id_column_count),
+ od_ (update_image_bind_ + update_column_count)
+ {
+ image_.version = 0;
+ select_image_version_ = 0;
+ insert_image_version_ = 0;
+ update_image_version_ = 0;
+ update_id_image_version_ = 0;
+
+ id_image_.version = 0;
+ id_image_version_ = 0;
+
+ //@@ TODO
+ // select_image_binding_.change_callback = image_.change_callback ();
+
+ std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_));
+ std::memset (update_image_bind_, 0, sizeof (update_image_bind_));
+ std::memset (select_image_bind_, 0, sizeof (select_image_bind_));
+ }
+
+ template <typename T>
+ void object_statements<T>::
+ load_delayed_ ()
+ {
+ database& db (connection ().database ());
+
+ delayed_loads dls;
+ swap_guard sg (*this, dls);
+
+ while (!dls.empty ())
+ {
+ delayed_load l (dls.back ());
+ typename object_cache_traits::insert_guard g (l.pos);
+ dls.pop_back ();
+
+ if (!object_traits::find_ (*this, l.id))
+ throw object_not_persistent ();
+
+ object_traits::callback (db, *l.obj, callback_event::pre_load);
+
+ // Our calls to init/load below can result in additional delayed
+ // loads being added to the delayed_ vector. We need to process
+ // those before we call the post callback.
+ //
+ object_traits::init (*l.obj, image (), db);
+ find_->stream_result ();
+ object_traits::load_ (*this, *l.obj); // Load containers, etc.
+
+ if (!delayed_.empty ())
+ load_delayed_ ();
+
+ // Temporarily unlock the statement for the post_load call so that
+ // it can load objects of this type recursively. This is safe to do
+ // because we have completely loaded the current object. Also the
+ // delayed_ list is clear before the unlock and should be clear on
+ // re-lock (since a callback can only call public API functions
+ // which will make sure all the delayed loads are processed before
+ // returning).
+ //
+ {
+ auto_unlock u (*this);
+ object_traits::callback (db, *l.obj, callback_event::post_load);
+ }
+
+ g.release ();
+ }
+ }
+
+ template <typename T>
+ void object_statements<T>::
+ clear_delayed_ ()
+ {
+ // Remove the objects from the session cache.
+ //
+ if (session::has_current ())
+ {
+ for (typename delayed_loads::iterator i (delayed_.begin ()),
+ e (delayed_.end ()); i != e; ++i)
+ {
+ object_cache_traits::erase (i->pos);
+ }
+ }
+
+ delayed_.clear ();
+ }
+
+ //
+ // object_statements_no_id
+ //
+
+ template <typename T>
+ object_statements_no_id<T>::
+ ~object_statements_no_id ()
+ {
+ }
+
+ template <typename T>
+ object_statements_no_id<T>::
+ object_statements_no_id (connection_type& conn)
+ : statements_base (conn),
+ select_image_binding_ (select_image_bind_, select_column_count),
+ insert_image_binding_ (insert_image_bind_, insert_column_count)
+ {
+ image_.version = 0;
+ select_image_version_ = 0;
+ insert_image_version_ = 0;
+
+ //@@ TODO
+ // select_image_binding_.change_callback = image_.change_callback ();
+
+ std::memset (insert_image_bind_, 0, sizeof (insert_image_bind_));
+ std::memset (select_image_bind_, 0, sizeof (select_image_bind_));
+ }
+ }
+}
diff --git a/odb/mssql/statement-cache.hxx b/odb/mssql/statement-cache.hxx
new file mode 100644
index 0000000..4b2ae37
--- /dev/null
+++ b/odb/mssql/statement-cache.hxx
@@ -0,0 +1,87 @@
+// file : odb/mssql/statement-cache.hxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#ifndef ODB_MSSQL_STATEMENT_CACHE_HXX
+#define ODB_MSSQL_STATEMENT_CACHE_HXX
+
+#include <odb/pre.hxx>
+
+#include <map>
+#include <typeinfo>
+
+#include <odb/forward.hxx>
+
+#include <odb/mssql/version.hxx>
+#include <odb/mssql/statements-base.hxx>
+#include <odb/mssql/object-statements.hxx>
+#include <odb/mssql/view-statements.hxx>
+
+#include <odb/details/shared-ptr.hxx>
+#include <odb/details/type-info.hxx>
+
+#include <odb/mssql/details/export.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ class connection;
+
+ class LIBODB_MSSQL_EXPORT statement_cache
+ {
+ public:
+ statement_cache (connection& conn)
+ : conn_ (conn)
+ {
+ }
+
+ template <typename T>
+ typename object_statements_selector<T>::type&
+ find_object ()
+ {
+ typedef typename object_statements_selector<T>::type object_statements;
+
+ map::iterator i (map_.find (&typeid (T)));
+
+ if (i != map_.end ())
+ return static_cast<object_statements&> (*i->second);
+
+ details::shared_ptr<object_statements> p (
+ new (details::shared) object_statements (conn_));
+
+ map_.insert (map::value_type (&typeid (T), p));
+ return *p;
+ }
+
+ template <typename T>
+ view_statements<T>&
+ find_view ()
+ {
+ map::iterator i (map_.find (&typeid (T)));
+
+ if (i != map_.end ())
+ return static_cast<view_statements<T>&> (*i->second);
+
+ details::shared_ptr<view_statements<T> > p (
+ new (details::shared) view_statements<T> (conn_));
+
+ map_.insert (map::value_type (&typeid (T), p));
+ return *p;
+ }
+
+ private:
+ typedef std::map<const std::type_info*,
+ details::shared_ptr<statements_base>,
+ details::type_info_comparator> map;
+
+ connection& conn_;
+ map map_;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_MSSQL_STATEMENT_CACHE_HXX
diff --git a/odb/mssql/statements-base.cxx b/odb/mssql/statements-base.cxx
new file mode 100644
index 0000000..0a99a08
--- /dev/null
+++ b/odb/mssql/statements-base.cxx
@@ -0,0 +1,17 @@
+// file : odb/mssql/statements-base.cxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#include <odb/mssql/statements-base.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ statements_base::
+ ~statements_base ()
+ {
+ }
+ }
+}
diff --git a/odb/mssql/statements-base.hxx b/odb/mssql/statements-base.hxx
new file mode 100644
index 0000000..b2ae55f
--- /dev/null
+++ b/odb/mssql/statements-base.hxx
@@ -0,0 +1,51 @@
+// file : odb/mssql/statements-base.hxx
+// author : Constantin Michael <constantin@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#ifndef ODB_MSSQL_STATEMENTS_BASE_HXX
+#define ODB_MSSQL_STATEMENTS_BASE_HXX
+
+#include <odb/pre.hxx>
+
+#include <odb/details/shared-ptr.hxx>
+
+#include <odb/mssql/version.hxx>
+#include <odb/mssql/forward.hxx> // connection
+
+#include <odb/mssql/details/export.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ class LIBODB_MSSQL_EXPORT statements_base: public details::shared_base
+ {
+ public:
+ typedef mssql::connection connection_type;
+
+ connection_type&
+ connection ()
+ {
+ return conn_;
+ }
+
+ public:
+ virtual
+ ~statements_base ();
+
+ protected:
+ statements_base (connection_type& conn)
+ : conn_ (conn)
+ {
+ }
+
+ protected:
+ connection_type& conn_;
+ };
+ }
+}
+
+#include <odb/post.hxx>
+
+#endif // ODB_MSSQL_STATEMENTS_BASE_HXX
diff --git a/odb/mssql/view-statements.hxx b/odb/mssql/view-statements.hxx
new file mode 100644
index 0000000..1e9cea6
--- /dev/null
+++ b/odb/mssql/view-statements.hxx
@@ -0,0 +1,83 @@
+// file : odb/mssql/view-statements.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#ifndef ODB_MSSQL_VIEW_STATEMENTS_HXX
+#define ODB_MSSQL_VIEW_STATEMENTS_HXX
+
+#include <odb/pre.hxx>
+
+#include <cstddef> // std::size_t
+
+#include <odb/forward.hxx>
+#include <odb/traits.hxx>
+
+#include <odb/mssql/mssql-types.hxx>
+#include <odb/mssql/version.hxx>
+#include <odb/mssql/statement.hxx>
+#include <odb/mssql/statements-base.hxx>
+
+namespace odb
+{
+ namespace mssql
+ {
+ template <typename T>
+ class view_statements: public statements_base
+ {
+ public:
+ typedef T view_type;
+ typedef odb::view_traits<view_type> view_traits;
+ typedef typename view_traits::pointer_type pointer_type;
+ typedef typename view_traits::image_type image_type;
+
+ public:
+ view_statements (connection_type&);
+
+ virtual
+ ~view_statements ();
+
+ // View image.
+ //
+ image_type&
+ image ()
+ {
+ return image_;
+ }
+
+ std::size_t
+ image_version () const
+ {
+ return image_version_;
+ }
+
+ void
+ image_version (std::size_t v)
+ {
+ image_version_ = v;
+ }
+
+ binding&
+ image_binding ()
+ {
+ return image_binding_;
+ }
+
+ private:
+ view_statements (const view_statements&);
+ view_statements& operator= (const view_statements&);
+
+ private:
+ image_type image_;
+ std::size_t image_version_;
+ binding image_binding_;
+ bind image_bind_[view_traits::column_count];
+ };
+ }
+}
+
+#include <odb/mssql/view-statements.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_MSSQL_VIEW_STATEMENTS_HXX
diff --git a/odb/mssql/view-statements.txx b/odb/mssql/view-statements.txx
new file mode 100644
index 0000000..e4e47d8
--- /dev/null
+++ b/odb/mssql/view-statements.txx
@@ -0,0 +1,33 @@
+// file : odb/mssql/view-statements.txx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC
+// license : ODB NCUEL; see accompanying LICENSE file
+
+#include <cstring> // std::memset
+
+namespace odb
+{
+ namespace mssql
+ {
+ template <typename T>
+ view_statements<T>::
+ ~view_statements ()
+ {
+ }
+
+ template <typename T>
+ view_statements<T>::
+ view_statements (connection_type& conn)
+ : statements_base (conn),
+ image_binding_ (image_bind_, view_traits::column_count)
+ {
+ image_.version = 0;
+ image_version_ = 0;
+
+ //@@ TODO
+ // image_binding_.change_callback = image_.change_callback ();
+
+ std::memset (image_bind_, 0, sizeof (image_bind_));
+ }
+ }
+}