aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2013-05-06 12:05:39 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2013-08-14 15:19:13 +0200
commit0745f84e2d5c7133f6ee6608487089d69d7ad519 (patch)
treebcba1aee153c18ef58396c86632de35360fb5950
parent79ccdd960976729e2d46e2d476f54b92c5348a5f (diff)
Add support for object sections
Sections are an optimization mechanism that allows the partitioning of data members of a persistent class into groups that can be separately loaded and/or updated.
-rw-r--r--odb/pgsql/database.hxx14
-rw-r--r--odb/pgsql/database.ixx14
-rw-r--r--odb/pgsql/forward.hxx3
-rw-r--r--odb/pgsql/polymorphic-object-statements.hxx42
-rw-r--r--odb/pgsql/section-statements.hxx203
-rw-r--r--odb/pgsql/section-statements.txx52
-rw-r--r--odb/pgsql/simple-object-statements.hxx112
-rw-r--r--odb/pgsql/simple-object-statements.txx1
8 files changed, 386 insertions, 55 deletions
diff --git a/odb/pgsql/database.hxx b/odb/pgsql/database.hxx
index 1b456fb..2a70e96 100644
--- a/odb/pgsql/database.hxx
+++ b/odb/pgsql/database.hxx
@@ -125,6 +125,12 @@ namespace odb
void
load (const typename object_traits<T>::id_type& id, T& object);
+ // Load (or reload, if it is already loaded) a section of an object.
+ //
+ template <typename T>
+ void
+ load (T& object, section&);
+
// Reload an object.
//
template <typename T>
@@ -195,6 +201,14 @@ namespace odb
void
update (const typename object_traits<T>::pointer_type& obj_ptr);
+ // Update a section of an object. Throws the section_not_loaded
+ // exception if the section is not loaded. Note also that this
+ // function does not clear the changed flag if it is set.
+ //
+ template <typename T>
+ void
+ update (const T& object, const section&);
+
// Make the object transient. Throw object_not_persistent if not
// found.
//
diff --git a/odb/pgsql/database.ixx b/odb/pgsql/database.ixx
index afc3ce7..809e4d4 100644
--- a/odb/pgsql/database.ixx
+++ b/odb/pgsql/database.ixx
@@ -108,6 +108,13 @@ namespace odb
}
template <typename T>
+ inline void database::
+ load (T& obj, section& s)
+ {
+ return load_<T, id_pgsql> (obj, s);
+ }
+
+ template <typename T>
inline typename object_traits<T>::pointer_type database::
find (const typename object_traits<T>::id_type& id)
{
@@ -249,6 +256,13 @@ namespace odb
template <typename T>
inline void database::
+ update (const T& obj, const section& s)
+ {
+ update_<T, id_pgsql> (obj, s);
+ }
+
+ template <typename T>
+ inline void database::
erase (const typename object_traits<T>::id_type& id)
{
return erase_<T, id_pgsql> (id);
diff --git a/odb/pgsql/forward.hxx b/odb/pgsql/forward.hxx
index d1a5931..470462e 100644
--- a/odb/pgsql/forward.hxx
+++ b/odb/pgsql/forward.hxx
@@ -70,6 +70,9 @@ namespace odb
template <typename T>
class smart_container_statements;
+ template <typename T, typename ST>
+ class section_statements;
+
class query_base;
}
diff --git a/odb/pgsql/polymorphic-object-statements.hxx b/odb/pgsql/polymorphic-object-statements.hxx
index 644a6a2..c538c49 100644
--- a/odb/pgsql/polymorphic-object-statements.hxx
+++ b/odb/pgsql/polymorphic-object-statements.hxx
@@ -183,8 +183,8 @@ namespace odb
base_statements_type;
typedef
- typename object_traits::container_statement_cache_type
- container_statement_cache_type;
+ typename object_traits::extra_statement_cache_type
+ extra_statement_cache_type;
typedef pgsql::insert_statement insert_statement_type;
typedef pgsql::select_statement select_statement_type;
@@ -294,6 +294,10 @@ namespace odb
binding&
id_image_binding () {return root_statements_.id_image_binding ();}
+ binding&
+ optimistic_id_image_binding () {
+ return root_statements_.optimistic_id_image_binding ();}
+
// Statements.
//
insert_statement_type&
@@ -373,35 +377,43 @@ namespace odb
return *erase_;
}
- // Container statement cache.
+ // Extra (container, section) statement cache.
//
- container_statement_cache_type&
- container_statment_cache ()
+ extra_statement_cache_type&
+ extra_statement_cache ()
{
- return container_statement_cache_.get (
+ return extra_statement_cache_.get (
conn_,
- root_statements_.id_image_binding (),
+ image_,
+ id_image_binding (),
+ &id_image_binding (), // Note, not id+version.
root_statements_.id_image_native_binding (),
object_traits::find_statement_types);
}
public:
- // select = total - id + base::select
+ // select = total - id - separate_load + base::select
// insert = total - inverse
- // update = total - inverse - id - readonly
+ // update = total - inverse - id - readonly - separate_update
//
static const std::size_t id_column_count =
object_traits::id_column_count;
static const std::size_t select_column_count =
- object_traits::column_count - id_column_count +
+ object_traits::column_count -
+ id_column_count -
+ object_traits::separate_load_column_count +
base_statements_type::select_column_count;
static const std::size_t insert_column_count =
- object_traits::column_count - object_traits::inverse_column_count;
+ object_traits::column_count -
+ object_traits::inverse_column_count;
- static const std::size_t update_column_count = insert_column_count -
- object_traits::id_column_count - object_traits::readonly_column_count;
+ static const std::size_t update_column_count =
+ insert_column_count -
+ object_traits::id_column_count -
+ object_traits::readonly_column_count -
+ object_traits::separate_update_column_count;
private:
polymorphic_derived_object_statements (
@@ -414,8 +426,8 @@ namespace odb
root_statements_type& root_statements_;
base_statements_type& base_statements_;
- container_statement_cache_ptr<container_statement_cache_type>
- container_statement_cache_;
+ extra_statement_cache_ptr<extra_statement_cache_type, image_type>
+ extra_statement_cache_;
image_type image_;
diff --git a/odb/pgsql/section-statements.hxx b/odb/pgsql/section-statements.hxx
new file mode 100644
index 0000000..b2f5c7b
--- /dev/null
+++ b/odb/pgsql/section-statements.hxx
@@ -0,0 +1,203 @@
+// file : odb/pgsql/section-statements.hxx
+// copyright : Copyright (c) 2005-2013 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#ifndef ODB_PGSQL_SECTION_STATEMENTS_HXX
+#define ODB_PGSQL_SECTION_STATEMENTS_HXX
+
+#include <odb/pre.hxx>
+
+#include <cstddef> // std::size_t
+
+#include <odb/forward.hxx>
+#include <odb/traits.hxx>
+
+#include <odb/pgsql/version.hxx>
+#include <odb/pgsql/binding.hxx>
+#include <odb/pgsql/statement.hxx>
+#include <odb/pgsql/pgsql-fwd.hxx> // Oid
+#include <odb/pgsql/details/export.hxx>
+
+namespace odb
+{
+ namespace pgsql
+ {
+ class connection;
+
+ // Template argument is the section traits type.
+ //
+ template <typename T, typename ST>
+ class section_statements
+ {
+ public:
+ typedef ST traits;
+
+ typedef typename traits::image_type image_type;
+
+ typedef pgsql::select_statement select_statement_type;
+ typedef pgsql::update_statement update_statement_type;
+
+ typedef pgsql::connection connection_type;
+
+ section_statements (connection_type&,
+ image_type&,
+ binding& id,
+ binding& idv,
+ native_binding& idn,
+ const Oid* idt);
+
+ connection_type&
+ connection () {return conn_;}
+
+ image_type&
+ image () {return image_;}
+
+ const binding&
+ id_binding () {return id_binding_;}
+
+ // Id and optimistic concurrency version (if any).
+ //
+ const binding&
+ idv_binding () {return idv_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_;}
+
+ bool*
+ select_image_truncated () {return select_image_truncated_;}
+
+ // 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_binding_version () const { return update_id_binding_version_;}
+
+ void
+ update_id_binding_version (std::size_t v) {update_id_binding_version_ = v;}
+
+ binding&
+ update_image_binding () {return update_image_binding_;}
+
+ //
+ // Statements.
+ //
+
+ select_statement_type&
+ select_statement ()
+ {
+ if (select_ == 0)
+ select_.reset (
+ new (details::shared) select_statement_type (
+ conn_,
+ traits::select_name,
+ traits::select_statement,
+ id_types_,
+ id_column_count,
+ id_binding_,
+ id_native_binding_,
+ select_image_binding_,
+ false));
+
+ return *select_;
+ }
+
+ update_statement_type&
+ update_statement ()
+ {
+ if (update_ == 0)
+ update_.reset (
+ new (details::shared) update_statement_type (
+ conn_,
+ traits::update_name,
+ traits::update_statement,
+ traits::update_types,
+ update_column_count + id_column_count +
+ managed_optimistic_update_column_count,
+ update_image_binding_,
+ update_image_native_binding_,
+ false));
+
+ return *update_;
+ }
+
+ public:
+ static const std::size_t id_column_count = traits::id_column_count;
+ static const std::size_t managed_optimistic_load_column_count =
+ traits::managed_optimistic_load_column_count;
+ static const std::size_t managed_optimistic_update_column_count =
+ traits::managed_optimistic_update_column_count;
+ static const std::size_t select_column_count = traits::load_column_count;
+ static const std::size_t update_column_count =
+ traits::update_column_count;
+
+ private:
+ section_statements (const section_statements&);
+ section_statements& operator= (const section_statements&);
+
+ protected:
+ connection_type& conn_;
+
+ // These come from object_statements.
+ //
+ image_type& image_;
+ binding& id_binding_;
+ binding& idv_binding_;
+ native_binding& id_native_binding_;
+ const Oid* id_types_;
+
+ // Select binding.
+ //
+ std::size_t select_image_version_;
+
+ static const std::size_t select_bind_count =
+ select_column_count != 0 || managed_optimistic_load_column_count != 0
+ ? select_column_count + managed_optimistic_load_column_count
+ : 1;
+
+ binding select_image_binding_;
+ bind select_image_bind_[select_bind_count];
+ bool select_image_truncated_[select_bind_count];
+
+ // Update binding.
+ //
+ std::size_t update_image_version_;
+ std::size_t update_id_binding_version_;
+
+ static const std::size_t update_bind_count =
+ update_column_count != 0 || managed_optimistic_update_column_count != 0
+ ? update_column_count + id_column_count +
+ managed_optimistic_update_column_count
+ : 1;
+
+ binding update_image_binding_;
+ bind update_image_bind_[update_bind_count];
+
+ native_binding update_image_native_binding_;
+ char* update_image_values_[update_bind_count];
+ int update_image_lengths_[update_bind_count];
+ int update_image_formats_[update_bind_count];
+
+ details::shared_ptr<select_statement_type> select_;
+ details::shared_ptr<update_statement_type> update_;
+ };
+ }
+}
+
+#include <odb/pgsql/section-statements.txx>
+
+#include <odb/post.hxx>
+
+#endif // ODB_PGSQL_SECTION_STATEMENTS_HXX
diff --git a/odb/pgsql/section-statements.txx b/odb/pgsql/section-statements.txx
new file mode 100644
index 0000000..d4463d1
--- /dev/null
+++ b/odb/pgsql/section-statements.txx
@@ -0,0 +1,52 @@
+// file : odb/pgsql/section-statements.txx
+// copyright : Copyright (c) 2005-2013 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cstring> // std::memset
+
+namespace odb
+{
+ namespace pgsql
+ {
+ template <typename T, typename ST>
+ section_statements<T, ST>::
+ section_statements (connection_type& conn,
+ image_type& im,
+ binding& id,
+ binding& idv,
+ native_binding& idn,
+ const Oid* idt)
+ : conn_ (conn),
+ image_ (im),
+ id_binding_ (id),
+ idv_binding_ (idv),
+ id_native_binding_ (idn),
+ id_types_ (idt),
+ select_image_binding_ (select_image_bind_,
+ select_column_count +
+ managed_optimistic_load_column_count),
+ update_image_binding_ (update_image_bind_,
+ update_column_count + id_column_count +
+ managed_optimistic_update_column_count),
+ update_image_native_binding_ (update_image_values_,
+ update_image_lengths_,
+ update_image_formats_,
+ update_column_count + id_column_count +
+ managed_optimistic_update_column_count)
+ {
+ select_image_version_ = 0;
+ update_image_version_ = 0;
+ update_id_binding_version_ = 0;
+
+ std::memset (select_image_bind_, 0, sizeof (select_image_bind_));
+ std::memset (
+ select_image_truncated_, 0, sizeof (select_image_truncated_));
+ std::memset (update_image_bind_, 0, sizeof (update_image_bind_));
+
+ for (std::size_t i (0);
+ i < select_column_count + managed_optimistic_load_column_count;
+ ++i)
+ select_image_bind_[i].truncated = select_image_truncated_ + i;
+ }
+ }
+}
diff --git a/odb/pgsql/simple-object-statements.hxx b/odb/pgsql/simple-object-statements.hxx
index f7e3949..5840c26 100644
--- a/odb/pgsql/simple-object-statements.hxx
+++ b/odb/pgsql/simple-object-statements.hxx
@@ -29,60 +29,70 @@ namespace odb
{
namespace pgsql
{
- // The container_statement_cache class is only defined (and used) in
+ // The extra_statement_cache class is only defined (and used) in
// the generated source file. However, object_statements may be
// referenced from another source file in the case of a polymorphic
- // hierarchy (though in this case the container statement cache is
+ // hierarchy (though in this case the extra statement cache is
// not used). As a result, we cannot have a by-value member and
// instead will store a pointer and lazily allocate the cache if
// and when needed. We will also need to store a pointer to the
// deleter function which will be initialized during allocation
// (at that point we know that the cache class is defined).
//
- template <typename T>
- struct container_statement_cache_ptr
+ template <typename T, typename I>
+ struct extra_statement_cache_ptr
{
+ typedef I image_type;
typedef pgsql::connection connection_type;
- container_statement_cache_ptr (): p_ (0) {}
- ~container_statement_cache_ptr ()
+ extra_statement_cache_ptr (): p_ (0) {}
+ ~extra_statement_cache_ptr ()
{
if (p_ != 0)
- (this->*deleter_) (0, 0, 0, 0);
+ (this->*deleter_) (0, 0, 0, 0, 0, 0);
}
T&
get (connection_type& c,
- binding& id, native_binding& idn, const Oid* idt)
+ image_type& im,
+ binding& id,
+ binding* idv,
+ native_binding& idn,
+ const Oid* idt)
{
if (p_ == 0)
- allocate (&c, &id, &idn, idt);
+ allocate (&c, &im, &id, (idv != 0 ? idv : &id), &idn, idt);
return *p_;
}
private:
void
- allocate (connection_type*, binding*, native_binding*, const Oid*);
+ allocate (connection_type*,
+ image_type*,
+ binding*, binding*, native_binding*, const Oid*);
private:
T* p_;
- void (container_statement_cache_ptr::*deleter_) (
- connection_type*, binding*, native_binding*, const Oid*);
+ void (extra_statement_cache_ptr::*deleter_) (
+ connection_type*,
+ image_type*,
+ binding*, binding*, native_binding*, const Oid*);
};
- template <typename T>
- void container_statement_cache_ptr<T>::
+ template <typename T, typename I>
+ void extra_statement_cache_ptr<T, I>::
allocate (connection_type* c,
- binding* id, native_binding* idn, const Oid* idt)
+ image_type* im,
+ binding* id, binding* idv, 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, *id, *idn, idt);
- deleter_ = &container_statement_cache_ptr<T>::allocate;
+ p_ = new T (*c, *im, *id, *idv, *idn, idt);
+ deleter_ = &extra_statement_cache_ptr<T, I>::allocate;
}
else
delete p_;
@@ -158,9 +168,18 @@ namespace odb
optimistic_data (bind*, char** nv, int* nl, int* nf);
+ binding*
+ id_image_binding () {return &id_image_binding_;}
+
+ native_binding*
+ id_image_native_binding () {return &id_image_native_binding_;}
+
+ const Oid*
+ id_image_types ()
+ {return object_traits::optimistic_erase_statement_types;}
+
// The id + optimistic column binding.
//
- std::size_t id_image_version_;
binding id_image_binding_;
native_binding id_image_native_binding_;
@@ -171,6 +190,15 @@ namespace odb
struct optimistic_data<T, false>
{
optimistic_data (bind*, char**, int*, int*) {}
+
+ binding*
+ id_image_binding () {return 0;}
+
+ native_binding*
+ id_image_native_binding () {return 0;}
+
+ const Oid*
+ id_image_types () {return 0;}
};
template <typename T>
@@ -189,8 +217,8 @@ namespace odb
pointer_cache_traits;
typedef
- typename object_traits::container_statement_cache_type
- container_statement_cache_type;
+ typename object_traits::extra_statement_cache_type
+ extra_statement_cache_type;
typedef pgsql::insert_statement insert_statement_type;
typedef pgsql::select_statement select_statement_type;
@@ -329,14 +357,10 @@ namespace odb
binding&
id_image_binding () {return id_image_binding_;}
- // Optimistic id + managed column image binding.
+ // Optimistic id + managed column image binding. It points to
+ // the same suffix as id binding and they are always updated
+ // at the same time.
//
- 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_;}
@@ -434,37 +458,44 @@ namespace odb
return *od_.erase_;
}
- // Container statement cache.
+ // Extra (container, section) statement cache.
//
- container_statement_cache_type&
- container_statment_cache ()
+ extra_statement_cache_type&
+ extra_statement_cache ()
{
- return container_statement_cache_.get (
+ return extra_statement_cache_.get (
conn_,
+ image_,
id_image_binding_,
+ od_.id_image_binding (),
id_image_native_binding_,
object_traits::find_statement_types);
}
public:
- // select = total
+ // select = total - separate_load
// insert = total - inverse - managed_optimistic - auto_id
- // update = total - inverse - managed_optimistic - id - readonly
+ // update = total - inverse - managed_optimistic - id - readonly -
+ // separate_update
//
static const std::size_t select_column_count =
- object_traits::column_count;
+ object_traits::column_count -
+ object_traits::separate_load_column_count;
static const std::size_t id_column_count =
object_traits::id_column_count;
static const std::size_t insert_column_count =
- object_traits::column_count - object_traits::inverse_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 -
+ static const std::size_t update_column_count =
+ insert_column_count -
(object_traits::auto_id ? 0 : id_column_count) -
- object_traits::readonly_column_count;
+ object_traits::readonly_column_count -
+ object_traits::separate_update_column_count;
static const std::size_t managed_optimistic_column_count =
object_traits::managed_optimistic_column_count;
@@ -481,8 +512,11 @@ namespace odb
clear_delayed_ ();
protected:
- container_statement_cache_ptr<container_statement_cache_type>
- container_statement_cache_;
+ template <typename T1>
+ friend class polymorphic_derived_object_statements;
+
+ extra_statement_cache_ptr<extra_statement_cache_type, image_type>
+ extra_statement_cache_;
image_type image_;
diff --git a/odb/pgsql/simple-object-statements.txx b/odb/pgsql/simple-object-statements.txx
index 8a8d2a8..999dc9c 100644
--- a/odb/pgsql/simple-object-statements.txx
+++ b/odb/pgsql/simple-object-statements.txx
@@ -29,7 +29,6 @@ namespace odb
object_traits::id_column_count +
object_traits::managed_optimistic_column_count)
{
- id_image_version_ = 0;
}
//