aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2013-02-05 15:50:07 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2013-02-05 15:50:07 +0200
commit32613d718b36a6c400d6f05da50d30b3fd25c3b8 (patch)
tree5e6816a5133fc4de18dc6442c727528bbaa6875c
parent3a9feb01e8cda69c41af126a7266ae7a6e545499 (diff)
Add support for change-tracking containers
ODB now supports "smart" ordered containers. Such containers get extra functions for updating and deleting individual elements. Based on this functionality implement two change-tracking containers: odb::vector (equivalent to std::vector) and QOdbList (equivalent to QList). New tests: common/container/change-tracking and qt/common/container/change- tracking.
-rw-r--r--odb/sqlite/container-statements.hxx291
-rw-r--r--odb/sqlite/container-statements.txx79
-rw-r--r--odb/sqlite/forward.hxx3
-rw-r--r--odb/sqlite/polymorphic-object-statements.hxx2
-rw-r--r--odb/sqlite/simple-object-statements.hxx21
5 files changed, 250 insertions, 146 deletions
diff --git a/odb/sqlite/container-statements.hxx b/odb/sqlite/container-statements.hxx
index a7b39bf..9217964 100644
--- a/odb/sqlite/container-statements.hxx
+++ b/odb/sqlite/container-statements.hxx
@@ -33,8 +33,6 @@ namespace odb
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 sqlite::insert_statement insert_statement_type;
@@ -43,7 +41,7 @@ namespace odb
typedef sqlite::connection connection_type;
- container_statements (connection_type&);
+ container_statements (connection_type&, binding& id_binding);
connection_type&
connection ()
@@ -64,182 +62,233 @@ namespace odb
const binding&
id_binding ()
{
- return *id_binding_;
+ return id_binding_;
}
- void
- id_binding (const binding& b)
+ // Data image. The image is split into the id (that comes as a
+ // binding) and index/key plus value which are in data_image_type.
+ // The select binding is a subset of the full binding (no id).
+ //
+ data_image_type&
+ data_image ()
{
- id_binding_ = &b;
+ return data_image_;
}
- // Condition image.
- //
- cond_image_type&
- cond_image ()
+ bind*
+ data_bind ()
{
- return cond_image_;
+ return insert_image_binding_.bind;
}
- std::size_t
- cond_image_version () const
+ bool
+ data_binding_test_version () const
{
- return cond_image_version_;
+ return data_id_binding_version_ != id_binding_.version ||
+ data_image_version_ != data_image_.version ||
+ insert_image_binding_.version == 0;
}
void
- cond_image_version (std::size_t v)
+ data_binding_update_version ()
{
- cond_image_version_ = v;
+ data_id_binding_version_ = id_binding_.version;
+ data_image_version_ = data_image_.version;
+ insert_image_binding_.version++;
+ select_image_binding_.version++;
}
- std::size_t
- cond_id_binding_version () const
+ bool*
+ select_image_truncated ()
{
- return cond_id_binding_version_;
+ return select_image_truncated_;
}
- void
- cond_id_binding_version (std::size_t v)
+ //
+ // Statements.
+ //
+
+ insert_statement_type&
+ insert_statement ()
{
- cond_id_binding_version_ = v;
+ if (insert_ == 0)
+ insert_.reset (
+ new (details::shared) insert_statement_type (
+ conn_, insert_text_, insert_image_binding_));
+
+ return *insert_;
}
- binding&
- cond_image_binding ()
+ select_statement_type&
+ select_statement ()
{
- return cond_image_binding_;
+ if (select_ == 0)
+ select_.reset (
+ new (details::shared) select_statement_type (
+ conn_,
+ select_text_,
+ id_binding_,
+ select_image_binding_));
+
+ return *select_;
}
- // Data image.
- //
- data_image_type&
- data_image ()
+ delete_statement_type&
+ delete_statement ()
{
- return data_image_;
+ if (delete_ == 0)
+ delete_.reset (
+ new (details::shared) delete_statement_type (
+ conn_, delete_text_, id_binding_));
+
+ return *delete_;
}
- std::size_t
- data_image_version () const
+ private:
+ container_statements (const container_statements&);
+ container_statements& operator= (const container_statements&);
+
+ protected:
+ connection_type& conn_;
+ binding& id_binding_;
+
+ functions_type functions_;
+
+ data_image_type data_image_;
+ std::size_t data_image_version_;
+ std::size_t data_id_binding_version_;
+
+ binding insert_image_binding_;
+
+ binding select_image_binding_;
+ bool* select_image_truncated_;
+
+ const char* insert_text_;
+ const char* select_text_;
+ const char* delete_text_;
+
+ details::shared_ptr<insert_statement_type> insert_;
+ details::shared_ptr<select_statement_type> select_;
+ details::shared_ptr<delete_statement_type> delete_;
+ };
+
+ template <typename T>
+ class smart_container_statements: public container_statements<T>
+ {
+ public:
+ typedef T traits;
+ typedef typename traits::cond_image_type cond_image_type;
+
+ typedef sqlite::update_statement update_statement_type;
+ typedef sqlite::delete_statement delete_statement_type;
+
+ typedef sqlite::connection connection_type;
+
+ smart_container_statements (connection_type&, binding& id_binding);
+
+ // Condition image. The image is split into the id (that comes as
+ // a binding) and index/key/value which is in cond_image_type.
+ //
+ cond_image_type&
+ cond_image ()
{
- return data_image_version_;
+ return cond_image_;
}
- void
- data_image_version (std::size_t v)
+ bind*
+ cond_bind ()
{
- data_image_version_ = v;
+ return cond_image_binding_.bind;
}
- std::size_t
- data_id_binding_version () const
+ bool
+ cond_binding_test_version () const
{
- return data_id_binding_version_;
+ return cond_id_binding_version_ != this->id_binding_.version ||
+ cond_image_version_ != cond_image_.version ||
+ cond_image_binding_.version == 0;
}
void
- data_id_binding_version (std::size_t v)
+ cond_binding_update_version ()
{
- data_id_binding_version_ = v;
+ cond_id_binding_version_ = this->id_binding_.version;
+ cond_image_version_ = cond_image_.version;
+ cond_image_binding_.version++;
}
- binding&
- data_image_binding ()
+ // Update image. The image is split as follows: value comes
+ // from the data image, id comes as binding, and index/key
+ // comes from the condition image.
+ //
+ bind*
+ update_bind ()
{
- return data_image_binding_;
+ return update_image_binding_.bind;
}
- binding&
- select_image_binding ()
+ bool
+ update_binding_test_version () const
{
- return select_image_binding_;
+ return update_id_binding_version_ != this->id_binding_.version ||
+ update_cond_image_version_ != cond_image_.version ||
+ update_data_image_version_ != this->data_image_.version ||
+ update_image_binding_.version == 0;
}
- bool*
- select_image_truncated ()
+ void
+ update_binding_update_version ()
{
- return select_image_truncated_;
+ update_id_binding_version_ = this->id_binding_.version;
+ update_cond_image_version_ = cond_image_.version;
+ update_data_image_version_ = this->data_image_.version;
+ update_image_binding_.version++;
}
//
// Statements.
//
- insert_statement_type&
- insert_one_statement ()
- {
- if (insert_one_ == 0)
- {
- insert_one_.reset (
- new (details::shared) insert_statement_type (
- conn_, insert_one_text_, data_image_binding_));
- }
-
- 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_,
- select_image_binding_));
- }
-
- return *select_all_;
- }
-
delete_statement_type&
- delete_all_statement ()
+ delete_statement ()
{
- if (delete_all_ == 0)
- {
- delete_all_.reset (
+ if (this->delete_ == 0)
+ this->delete_.reset (
new (details::shared) delete_statement_type (
- conn_, delete_all_text_, cond_image_binding_));
- }
+ this->conn_,
+ this->delete_text_,
+ this->cond_image_binding_));
- return *delete_all_;
+ return *this->delete_;
}
- private:
- container_statements (const container_statements&);
- container_statements& operator= (const container_statements&);
+ update_statement_type&
+ update_statement ()
+ {
+ if (update_ == 0)
+ update_.reset (
+ new (details::shared) update_statement_type (
+ this->conn_,
+ update_text_,
+ update_image_binding_));
+
+ return *update_;
+ }
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_;
- data_image_type data_image_;
- std::size_t data_image_version_;
- std::size_t data_id_binding_version_;
+ std::size_t update_id_binding_version_;
+ std::size_t update_cond_image_version_;
+ std::size_t update_data_image_version_;
+ binding update_image_binding_;
- binding data_image_binding_;
+ const char* update_text_;
- // Skips the id from data_image_binding.
- //
- binding select_image_binding_;
- bool* select_image_truncated_;
-
- 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_;
+ details::shared_ptr<update_statement_type> update_;
};
// Template argument is the generated concrete container traits type.
@@ -252,18 +301,32 @@ namespace odb
typedef typename T::statements_type base;
typedef sqlite::connection connection_type;
- container_statements_impl (connection_type&);
+ container_statements_impl (connection_type&, binding&);
private:
container_statements_impl (const container_statements_impl&);
container_statements_impl& operator= (const container_statements_impl&);
private:
- bind cond_image_bind_[traits::cond_column_count];
bind data_image_bind_[traits::data_column_count];
- bool select_image_truncated_array_[traits::data_column_count-
+ bool select_image_truncated_array_[traits::data_column_count -
traits::id_column_count];
};
+
+ template <typename T>
+ class smart_container_statements_impl: public container_statements_impl<T>
+ {
+ public:
+ typedef T traits;
+ typedef sqlite::connection connection_type;
+
+ smart_container_statements_impl (connection_type&, binding&);
+
+ private:
+ bind cond_image_bind_[traits::cond_column_count];
+ bind update_image_bind_[traits::value_column_count +
+ traits::cond_column_count];
+ };
}
}
diff --git a/odb/sqlite/container-statements.txx b/odb/sqlite/container-statements.txx
index 19ecfdc..4d575b7 100644
--- a/odb/sqlite/container-statements.txx
+++ b/odb/sqlite/container-statements.txx
@@ -11,48 +11,61 @@ namespace odb
{
// container_statements
//
-
template <typename T>
container_statements<T>::
- container_statements (connection_type& conn)
+ container_statements (connection_type& conn, binding& id)
: conn_ (conn),
- functions_ (this,
- &traits::insert_one,
- &traits::load_all,
- &traits::delete_all),
- id_binding_ (0),
+ id_binding_ (id),
+ functions_ (this),
+ insert_image_binding_ (0, 0), // Initialized by impl.
+ select_image_binding_ (0, 0) // Initialized by impl.
+ {
+ functions_.insert_ = &traits::insert;
+ functions_.select_ = &traits::select;
+ functions_.delete__ = &traits::delete_;
+
+ data_image_.version = 0;
+ data_image_version_ = 0;
+ data_id_binding_version_ = 0;
+ }
+
+ // smart_container_statements
+ //
+ template <typename T>
+ smart_container_statements<T>::
+ smart_container_statements (connection_type& conn, binding& id)
+ : container_statements<T> (conn, id),
cond_image_binding_ (0, 0), // Initialized by impl.
- data_image_binding_ (0, 0), // Initialized by impl.
- select_image_binding_ (0, 0) // Initialized by impl.
+ update_image_binding_ (0, 0) // Initialized by impl.
{
+ this->functions_.update_ = &traits::update;
+
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;
+ update_id_binding_version_ = 0;
+ update_cond_image_version_ = 0;
+ update_data_image_version_ = 0;
}
+ // container_statements_impl
+ //
template <typename T>
container_statements_impl<T>::
- container_statements_impl (connection_type& conn)
- : base (conn)
+ container_statements_impl (connection_type& conn, binding& id)
+ : base (conn, id)
{
this->select_image_truncated_ = select_image_truncated_array_;
- this->cond_image_binding_.bind = cond_image_bind_;
- this->cond_image_binding_.count = traits::cond_column_count;
-
- this->data_image_binding_.bind = data_image_bind_;
- this->data_image_binding_.count = traits::data_column_count;
+ this->insert_image_binding_.bind = data_image_bind_;
+ this->insert_image_binding_.count = traits::data_column_count;
this->select_image_binding_.bind = data_image_bind_ +
traits::id_column_count;
this->select_image_binding_.count = traits::data_column_count -
traits::id_column_count;
- std::memset (cond_image_bind_, 0, sizeof (cond_image_bind_));
std::memset (data_image_bind_, 0, sizeof (data_image_bind_));
std::memset (select_image_truncated_array_,
0,
@@ -64,9 +77,29 @@ namespace odb
data_image_bind_[i + traits::id_column_count].truncated =
select_image_truncated_array_ + i;
- this->insert_one_text_ = traits::insert_one_statement;
- this->select_all_text_ = traits::select_all_statement;
- this->delete_all_text_ = traits::delete_all_statement;
+ this->insert_text_ = traits::insert_statement;
+ this->select_text_ = traits::select_statement;
+ this->delete_text_ = traits::delete_statement;
+ }
+
+ // smart_container_statements_impl
+ //
+ template <typename T>
+ smart_container_statements_impl<T>::
+ smart_container_statements_impl (connection_type& conn, binding& id)
+ : container_statements_impl<T> (conn, id)
+ {
+ this->cond_image_binding_.bind = cond_image_bind_;
+ this->cond_image_binding_.count = traits::cond_column_count;
+
+ this->update_image_binding_.bind = update_image_bind_;
+ this->update_image_binding_.count = traits::value_column_count +
+ traits::cond_column_count;
+
+ std::memset (cond_image_bind_, 0, sizeof (cond_image_bind_));
+ std::memset (update_image_bind_, 0, sizeof (update_image_bind_));
+
+ this->update_text_ = traits::update_statement;
}
}
}
diff --git a/odb/sqlite/forward.hxx b/odb/sqlite/forward.hxx
index 382284e..389b078 100644
--- a/odb/sqlite/forward.hxx
+++ b/odb/sqlite/forward.hxx
@@ -67,6 +67,9 @@ namespace odb
template <typename T>
class container_statements;
+ template <typename T>
+ class smart_container_statements;
+
class query_base;
class query_params;
}
diff --git a/odb/sqlite/polymorphic-object-statements.hxx b/odb/sqlite/polymorphic-object-statements.hxx
index 50d66a3..64d9a7d 100644
--- a/odb/sqlite/polymorphic-object-statements.hxx
+++ b/odb/sqlite/polymorphic-object-statements.hxx
@@ -353,7 +353,7 @@ namespace odb
container_statement_cache_type&
container_statment_cache ()
{
- return container_statement_cache_.get (conn_);
+ return container_statement_cache_.get (conn_, id_image_binding ());
}
public:
diff --git a/odb/sqlite/simple-object-statements.hxx b/odb/sqlite/simple-object-statements.hxx
index 9ff3faf..9fe3675 100644
--- a/odb/sqlite/simple-object-statements.hxx
+++ b/odb/sqlite/simple-object-statements.hxx
@@ -45,36 +45,41 @@ namespace odb
typedef sqlite::connection connection_type;
container_statement_cache_ptr (): p_ (0) {}
- ~container_statement_cache_ptr () {if (p_ != 0) (this->*deleter_) (0);}
+ ~container_statement_cache_ptr ()
+ {
+ if (p_ != 0)
+ (this->*deleter_) (0, 0);
+ }
T&
- get (connection_type& c)
+ get (connection_type& c, binding& id)
{
if (p_ == 0)
- allocate (&c);
+ allocate (&c, &id);
return *p_;
}
private:
void
- allocate (connection_type*);
+ allocate (connection_type*, binding*);
private:
T* p_;
- void (container_statement_cache_ptr::*deleter_) (connection_type*);
+ void (container_statement_cache_ptr::*deleter_) (
+ connection_type*, binding*);
};
template <typename T>
void container_statement_cache_ptr<T>::
- allocate (connection_type* c)
+ allocate (connection_type* c, binding* id)
{
// To reduce object code size, this function acts as both allocator
// and deleter.
//
if (p_ == 0)
{
- p_ = new T (*c);
+ p_ = new T (*c, *id);
deleter_ = &container_statement_cache_ptr<T>::allocate;
}
else
@@ -416,7 +421,7 @@ namespace odb
container_statement_cache_type&
container_statment_cache ()
{
- return container_statement_cache_.get (conn_);
+ return container_statement_cache_.get (conn_, id_image_binding_);
}
public: