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
commit4443c9284e35c070478045b4e5963c64cd108e42 (patch)
tree57f395b2c18dd1a946046e9c6c2eb155fd941a1c
parent4e33546b4c0a29d879a38029ad103374d4a779ef (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/pgsql/container-statements.hxx393
-rw-r--r--odb/pgsql/container-statements.txx145
-rw-r--r--odb/pgsql/forward.hxx3
-rw-r--r--odb/pgsql/polymorphic-object-statements.hxx6
-rw-r--r--odb/pgsql/simple-object-statements.hxx27
5 files changed, 365 insertions, 209 deletions
diff --git a/odb/pgsql/container-statements.hxx b/odb/pgsql/container-statements.hxx
index cf0e0b8..6ed9f37 100644
--- a/odb/pgsql/container-statements.hxx
+++ b/odb/pgsql/container-statements.hxx
@@ -16,7 +16,6 @@
#include <odb/pgsql/binding.hxx>
#include <odb/pgsql/statement.hxx>
#include <odb/pgsql/pgsql-fwd.hxx> // Oid
-#include <odb/pgsql/pgsql-oid.hxx>
#include <odb/pgsql/details/export.hxx>
namespace odb
@@ -35,8 +34,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 pgsql::insert_statement insert_statement_type;
@@ -45,7 +42,10 @@ namespace odb
typedef pgsql::connection connection_type;
- container_statements (connection_type&);
+ container_statements (connection_type&,
+ binding& id,
+ native_binding& idn,
+ const Oid* idt);
connection_type&
connection ()
@@ -66,227 +66,284 @@ 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)
- {
- cond_id_binding_version_ = v;
- }
+ //
+ // Statements.
+ //
- binding&
- cond_image_binding ()
+ insert_statement_type&
+ insert_statement ()
{
- return cond_image_binding_;
- }
+ if (insert_ == 0)
+ insert_.reset (
+ new (details::shared) insert_statement_type (
+ conn_,
+ insert_name_,
+ insert_text_,
+ insert_types_,
+ insert_count_,
+ insert_image_binding_,
+ insert_image_native_binding_,
+ false,
+ false));
- native_binding&
- cond_image_native_binding ()
- {
- return cond_image_native_binding_;
+ return *insert_;
}
- // Data image.
- //
- data_image_type&
- data_image ()
+ select_statement_type&
+ select_statement ()
{
- return data_image_;
+ if (select_ == 0)
+ select_.reset (
+ new (details::shared) select_statement_type (
+ conn_,
+ select_name_,
+ select_text_,
+ id_types_,
+ id_binding_.count,
+ id_binding_,
+ id_native_binding_,
+ select_image_binding_,
+ false));
+
+ return *select_;
}
- std::size_t
- data_image_version () const
+ delete_statement_type&
+ delete_statement ()
{
- return data_image_version_;
+ if (delete_ == 0)
+ delete_.reset (
+ new (details::shared) delete_statement_type (
+ conn_,
+ delete_name_,
+ delete_text_,
+ id_types_,
+ id_binding_.count,
+ id_binding_,
+ id_native_binding_,
+ false));
+
+ return *delete_;
}
- void
- data_image_version (std::size_t v)
+ private:
+ container_statements (const container_statements&);
+ container_statements& operator= (const container_statements&);
+
+ protected:
+ connection_type& conn_;
+ binding& id_binding_;
+ native_binding& id_native_binding_;
+ const Oid* id_types_;
+
+ 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_;
+ native_binding insert_image_native_binding_;
+
+ binding select_image_binding_;
+ bool* select_image_truncated_;
+
+ const char* insert_name_;
+ const char* insert_text_;
+ const Oid* insert_types_;
+ std::size_t insert_count_;
+
+ const char* select_name_;
+ const char* select_text_;
+
+ const char* delete_name_;
+ 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 pgsql::update_statement update_statement_type;
+ typedef pgsql::delete_statement delete_statement_type;
+
+ typedef pgsql::connection connection_type;
+
+ smart_container_statements (connection_type&,
+ binding& id,
+ native_binding& idn,
+ const Oid* idt);
+
+ // 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 ()
{
- data_image_version_ = v;
+ return cond_image_;
}
- std::size_t
- data_id_binding_version () const
+ bind*
+ cond_bind ()
{
- return data_id_binding_version_;
+ return cond_image_binding_.bind;
}
- void
- data_id_binding_version (std::size_t v)
+ bool
+ cond_binding_test_version () const
{
- data_id_binding_version_ = v;
+ return cond_id_binding_version_ != this->id_binding_.version ||
+ cond_image_version_ != cond_image_.version ||
+ cond_image_binding_.version == 0;
}
- binding&
- data_image_binding ()
+ void
+ cond_binding_update_version ()
{
- return data_image_binding_;
+ cond_id_binding_version_ = this->id_binding_.version;
+ cond_image_version_ = cond_image_.version;
+ cond_image_binding_.version++;
}
- native_binding&
- data_image_native_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_native_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_name_,
- insert_one_text_,
- insert_one_types_,
- insert_one_count_,
- data_image_binding_,
- data_image_native_binding_,
- false,
- false));
- }
-
- return *insert_one_;
- }
-
- select_statement_type&
- select_all_statement ()
+ delete_statement_type&
+ delete_statement ()
{
- if (select_all_ == 0)
- {
- select_all_.reset (
- new (details::shared) select_statement_type (
- conn_,
- select_all_name_,
- select_all_text_,
- select_all_types_,
- select_all_count_,
+ if (this->delete_ == 0)
+ this->delete_.reset (
+ new (details::shared) delete_statement_type (
+ this->conn_,
+ this->delete_name_,
+ this->delete_text_,
+ delete_types_,
+ delete_count_,
cond_image_binding_,
cond_image_native_binding_,
- select_image_binding_,
false));
- }
- return *select_all_;
+ return *this->delete_;
}
- delete_statement_type&
- delete_all_statement ()
+ update_statement_type&
+ update_statement ()
{
- if (delete_all_ == 0)
- {
- delete_all_.reset (
- new (details::shared) delete_statement_type (
- conn_,
- delete_all_name_,
- delete_all_text_,
- delete_all_types_,
- delete_all_count_,
- cond_image_binding_,
- cond_image_native_binding_,
+ if (update_ == 0)
+ update_.reset (
+ new (details::shared) update_statement_type (
+ this->conn_,
+ update_name_,
+ update_text_,
+ update_types_,
+ update_count_,
+ update_image_binding_,
+ update_image_native_binding_,
false));
- }
- return *delete_all_;
+ return *update_;
}
- 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_;
native_binding cond_image_native_binding_;
- data_image_type data_image_;
- std::size_t data_image_version_;
- std::size_t data_id_binding_version_;
-
- binding data_image_binding_;
- native_binding data_image_native_binding_;
+ 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_;
+ native_binding update_image_native_binding_;
- // Skips the id from data_image_binding.
- //
- binding select_image_binding_;
- bool* select_image_truncated_;
+ const char* update_name_;
+ const char* update_text_;
+ const Oid* update_types_;
+ std::size_t update_count_;
- const char* insert_one_name_;
- const char* insert_one_text_;
- const Oid* insert_one_types_;
- std::size_t insert_one_count_;
+ const Oid* delete_types_;
+ std::size_t delete_count_;
- const char* select_all_name_;
- const char* select_all_text_;
- const Oid* select_all_types_;
- std::size_t select_all_count_;
-
- const char* delete_all_name_;
- const char* delete_all_text_;
- const Oid* delete_all_types_;
- std::size_t delete_all_count_;
-
- 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.
@@ -299,18 +356,15 @@ namespace odb
typedef typename T::statements_type base;
typedef pgsql::connection connection_type;
- container_statements_impl (connection_type&);
-
+ container_statements_impl (connection_type&,
+ binding&,
+ native_binding&,
+ const Oid*);
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];
- char* cond_image_values_[traits::cond_column_count];
- int cond_image_lengths_[traits::cond_column_count];
- int cond_image_formats_[traits::cond_column_count];
-
bind data_image_bind_[traits::data_column_count];
char* data_image_values_[traits::data_column_count];
int data_image_lengths_[traits::data_column_count];
@@ -319,6 +373,33 @@ namespace odb
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 pgsql::connection connection_type;
+
+ smart_container_statements_impl (connection_type&,
+ binding&,
+ native_binding&,
+ const Oid*);
+ private:
+ bind cond_image_bind_[traits::cond_column_count];
+ char* cond_image_values_[traits::cond_column_count];
+ int cond_image_lengths_[traits::cond_column_count];
+ int cond_image_formats_[traits::cond_column_count];
+
+ bind update_image_bind_[traits::value_column_count +
+ traits::cond_column_count];
+ char* update_image_values_[traits::value_column_count +
+ traits::cond_column_count];
+ int update_image_lengths_[traits::value_column_count +
+ traits::cond_column_count];
+ int update_image_formats_[traits::value_column_count +
+ traits::cond_column_count];
+ };
}
}
diff --git a/odb/pgsql/container-statements.txx b/odb/pgsql/container-statements.txx
index 7008cbb..2349b92 100644
--- a/odb/pgsql/container-statements.txx
+++ b/odb/pgsql/container-statements.txx
@@ -11,60 +11,80 @@ namespace odb
{
// container_statements
//
-
template <typename T>
container_statements<T>::
- container_statements (connection_type& conn)
+ container_statements (connection_type& conn,
+ binding& id,
+ native_binding& idn,
+ const Oid* idt)
: conn_ (conn),
- functions_ (this,
- &traits::insert_one,
- &traits::load_all,
- &traits::delete_all),
- id_binding_ (0),
- cond_image_binding_ (0, 0), // Initialized by impl.
- cond_image_native_binding_ (0, 0, 0, 0), // Initialized by impl.
- data_image_binding_ (0, 0), // Initialized by impl.
- data_image_native_binding_ (0, 0, 0, 0), // Initialized by impl.
- select_image_binding_ (0, 0) // Initialized by impl.
+ id_binding_ (id),
+ id_native_binding_ (idn),
+ id_types_ (idt),
+ functions_ (this),
+ insert_image_binding_ (0, 0), // Initialized by impl.
+ insert_image_native_binding_ (0, 0, 0, 0), // Initialized by impl.
+ select_image_binding_ (0, 0) // Initialized by impl.
{
- cond_image_.version = 0;
- cond_image_version_ = 0;
- cond_id_binding_version_ = 0;
+ 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,
+ native_binding& idn,
+ const Oid* idt)
+ : container_statements<T> (conn, id, idn, idt),
+ cond_image_binding_ (0, 0), // Initialized by impl.
+ cond_image_native_binding_ (0, 0, 0, 0), // Initialized by impl.
+ update_image_binding_ (0, 0), // Initialized by impl.
+ update_image_native_binding_ (0, 0, 0, 0) // Initialized by impl.
+ {
+ this->functions_.update_ = &traits::update;
+
+ cond_image_.version = 0;
+ cond_image_version_ = 0;
+ cond_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,
+ native_binding& idn,
+ const Oid* idt)
+ : base (conn, id, idn, idt)
{
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;
- this->cond_image_native_binding_.values = cond_image_values_;
- this->cond_image_native_binding_.lengths = cond_image_lengths_;
- this->cond_image_native_binding_.formats = cond_image_formats_;
- this->cond_image_native_binding_.count = traits::cond_column_count;
-
- this->data_image_native_binding_.values = data_image_values_;
- this->data_image_native_binding_.lengths = data_image_lengths_;
- this->data_image_native_binding_.formats = data_image_formats_;
- this->data_image_native_binding_.count = traits::data_column_count;
+ this->insert_image_native_binding_.values = data_image_values_;
+ this->insert_image_native_binding_.lengths = data_image_lengths_;
+ this->insert_image_native_binding_.formats = data_image_formats_;
+ this->insert_image_native_binding_.count = traits::data_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,
@@ -76,20 +96,57 @@ namespace odb
data_image_bind_[i + traits::id_column_count].truncated =
select_image_truncated_array_ + i;
- this->insert_one_name_ = traits::insert_one_name;
- this->insert_one_text_ = traits::insert_one_statement;
- this->insert_one_types_ = traits::insert_one_types;
- this->insert_one_count_ = traits::data_column_count;
+ this->insert_name_ = traits::insert_name;
+ this->insert_text_ = traits::insert_statement;
+ this->insert_types_ = traits::insert_types;
+ this->insert_count_ = traits::data_column_count;
+
+ this->select_name_ = traits::select_name;
+ this->select_text_ = traits::select_statement;
+
+ this->delete_name_ = traits::delete_name;
+ 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,
+ native_binding& idn,
+ const Oid* idt)
+ : container_statements_impl<T> (conn, id, idn, idt)
+ {
+ 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;
+
+ this->cond_image_native_binding_.values = cond_image_values_;
+ this->cond_image_native_binding_.lengths = cond_image_lengths_;
+ this->cond_image_native_binding_.formats = cond_image_formats_;
+ this->cond_image_native_binding_.count = traits::cond_column_count;
+
+ this->update_image_native_binding_.values = update_image_values_;
+ this->update_image_native_binding_.lengths = update_image_lengths_;
+ this->update_image_native_binding_.formats = update_image_formats_;
+ this->update_image_native_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->select_all_name_ = traits::select_all_name;
- this->select_all_text_ = traits::select_all_statement;
- this->select_all_types_ = traits::select_all_types;
- this->select_all_count_ = traits::cond_column_count;
+ this->update_name_ = traits::update_name;
+ this->update_text_ = traits::update_statement;
+ this->update_types_ = traits::update_types;
+ this->update_count_ = traits::value_column_count +
+ traits::cond_column_count;
- this->delete_all_name_ = traits::delete_all_name;
- this->delete_all_text_ = traits::delete_all_statement;
- this->delete_all_types_ = traits::delete_all_types;
- this->delete_all_count_ = traits::cond_column_count;
+ this->delete_types_ = traits::delete_types;
+ this->delete_count_ = traits::cond_column_count;
}
}
}
diff --git a/odb/pgsql/forward.hxx b/odb/pgsql/forward.hxx
index d028f4d..7799d1d 100644
--- a/odb/pgsql/forward.hxx
+++ b/odb/pgsql/forward.hxx
@@ -67,6 +67,9 @@ namespace odb
template <typename T>
class container_statements;
+ template <typename T>
+ class smart_container_statements;
+
class query_base;
}
diff --git a/odb/pgsql/polymorphic-object-statements.hxx b/odb/pgsql/polymorphic-object-statements.hxx
index 2f1a03a..6109597 100644
--- a/odb/pgsql/polymorphic-object-statements.hxx
+++ b/odb/pgsql/polymorphic-object-statements.hxx
@@ -378,7 +378,11 @@ namespace odb
container_statement_cache_type&
container_statment_cache ()
{
- return container_statement_cache_.get (conn_);
+ return container_statement_cache_.get (
+ conn_,
+ root_statements_.id_image_binding (),
+ root_statements_.id_image_native_binding (),
+ object_traits::find_statement_types);
}
public:
diff --git a/odb/pgsql/simple-object-statements.hxx b/odb/pgsql/simple-object-statements.hxx
index 772ff24..3dbdff3 100644
--- a/odb/pgsql/simple-object-statements.hxx
+++ b/odb/pgsql/simple-object-statements.hxx
@@ -45,36 +45,43 @@ namespace odb
typedef pgsql::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, 0, 0);
+ }
T&
- get (connection_type& c)
+ get (connection_type& c,
+ binding& id, native_binding& idn, const Oid* idt)
{
if (p_ == 0)
- allocate (&c);
+ allocate (&c, &id, &idn, idt);
return *p_;
}
private:
void
- allocate (connection_type*);
+ allocate (connection_type*, binding*, native_binding*, const Oid*);
private:
T* p_;
- void (container_statement_cache_ptr::*deleter_) (connection_type*);
+ void (container_statement_cache_ptr::*deleter_) (
+ connection_type*, binding*, native_binding*, const Oid*);
};
template <typename T>
void container_statement_cache_ptr<T>::
- allocate (connection_type* c)
+ allocate (connection_type* c,
+ binding* id, native_binding* idn, const Oid* idt)
{
// 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, *idn, idt);
deleter_ = &container_statement_cache_ptr<T>::allocate;
}
else
@@ -432,7 +439,11 @@ namespace odb
container_statement_cache_type&
container_statment_cache ()
{
- return container_statement_cache_.get (conn_);
+ return container_statement_cache_.get (
+ conn_,
+ id_image_binding_,
+ id_image_native_binding_,
+ object_traits::find_statement_types);
}
public: